Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Object.createFrom() #539

Merged
merged 10 commits into from
Oct 12, 2022
53 changes: 53 additions & 0 deletions docs/docs/standard-lib/object.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
---
layout: default
title: Object
nav_order: 17
parent: Standard Library
---

# Object
{: .no_toc }

## Table of contents
{: .no_toc .text-delta }

1. TOC
{:toc}

---

## Object

To make use of the Object module an import is required.

```cs
import Object;
```

### Object.getClassRef(string)

This method will attempt to get a class reference from the class name provided as a string.

Returns a Result and unwraps to an Object upon success.

**NOTE:** This currently only works if the class is defined in the global scope

```cs
class Test {}

Object.getClassRef("Test").unwrap(); // <Cls Test>
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is there an easy way to get the name of the class from an object? I know we have a getAttributes method but I don't believe it includes the name of the class. That might be a nice addition so this can be even more dynamic.

Copy link
Member Author

@Jason2605 Jason2605 Oct 11, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

When you say class name, do you mean an actual reference to the class or do you mean the string representation of the class name?

For example, if you already have the object you can get the class reference via: https://dictu-lang.com/docs/classes/#_class

Copy link
Contributor

@briandowns briandowns Oct 11, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The string representation of the class name.

Copy link
Member Author

@Jason2605 Jason2605 Oct 11, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ah there's currently no way to turn a class reference into a string'd name. We could add a _name attribute similar to _class to classes

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That would be cool.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should be added as part of #543

Now it would be:

class Test {}

print(Test._name);
print(Test()._class._name);

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Very cool!

```

### Object.createFrom(string)

This method will attempt to create a new object from the class name provided as a string.

Returns a Result and unwraps to an Object upon success.

**NOTE:** This currently only works if the class is defined in the global scope

```cs
class Test {}

Object.createFrom("Test").unwrap(); // <Test instance>
```
3 changes: 2 additions & 1 deletion scripts/generate.du
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,8 @@ var files = [
'src/vm/datatypes/result/result',
'src/optionals/unittest/unittest',
'src/optionals/env/env',
'src/optionals/http/http'
'src/optionals/http/http',
'src/optionals/object/object'
];

for (var i = 0; i < files.len(); i += 1) {
Expand Down
9 changes: 9 additions & 0 deletions src/optionals/object/object-source.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
#define DICTU_OBJECT_SOURCE "import Object;\n" \
"\n" \
"def createFrom(className, ...arguments) {\n" \
" return Object.__getClassRef(className).matchWrap(\n" \
" def (klass) => klass(...arguments),\n" \
" def (error) => error\n" \
" );\n" \
"}\n" \

69 changes: 69 additions & 0 deletions src/optionals/object/object.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
#include "object.h"

#include "object-source.h"

static Value objectGetClassRefImpl(DictuVM *vm, int argCount, Value *args, bool internal) {
if (argCount != 1) {
runtimeError(vm, "getClassRef() takes 1 argument (%d given)", argCount);
return EMPTY_VAL;
}

if (!IS_STRING(args[0])) {
runtimeError(vm, "getClassRef() argument must be a string");
return EMPTY_VAL;
}

ObjString *classString = AS_STRING(args[0]);

Value klass;
CallFrame *frame;
if (internal) {
// -2 as we want to go to the callee site, not the Object.du code
frame = &vm->frames[vm->frameCount - 2];
} else {
frame = &vm->frames[vm->frameCount - 1];
}

if (tableGet(&frame->closure->function->module->values, classString, &klass) && IS_CLASS(klass)) {
return newResultSuccess(vm, klass);
}

char *error = ALLOCATE(vm, char, classString->length + 26);
memcpy(error, classString->chars, classString->length);
memcpy(error + classString->length, " class could not be found", 25);
error[classString->length + 25] = '\0';

Value result = newResultError(vm, error);

FREE_ARRAY(vm, char, error, classString->length + 26);

return result;
}

static Value objectGetClassRef(DictuVM *vm, int argCount, Value *args) {
return objectGetClassRefImpl(vm, argCount, args, false);
}

static Value objectGetClassRefInternal(DictuVM *vm, int argCount, Value *args) {
return objectGetClassRefImpl(vm, argCount, args, true);
}

Value createObjectModule(DictuVM *vm) {
ObjClosure *closure = compileModuleToClosure(vm, "Object", DICTU_OBJECT_SOURCE);

if (closure == NULL) {
return EMPTY_VAL;
}

push(vm, OBJ_VAL(closure));

/**
* Define Object methods
*/
defineNative(vm, &closure->function->module->values, "__getClassRef", objectGetClassRefInternal);
defineNative(vm, &closure->function->module->values, "getClassRef", objectGetClassRef);

pop(vm);

return OBJ_VAL(closure);
}
8 changes: 8 additions & 0 deletions src/optionals/object/object.du
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
import Object;

def createFrom(className, ...arguments) {
return Object.__getClassRef(className).matchWrap(
def (klass) => klass(...arguments),
def (error) => error
);
}
11 changes: 11 additions & 0 deletions src/optionals/object/object.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
#ifndef dictu_object_module_h
#define dictu_object_module_h

#include <stdlib.h>

#include "../optionals.h"
#include "../../vm/vm.h"

Value createObjectModule(DictuVM *vm);

#endif //dictu_object_module_h
1 change: 1 addition & 0 deletions src/optionals/optionals.c
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ BuiltinModules modules[] = {
{"System", &createSystemModule, false},
{"UnitTest", &createUnitTestModule, true},
{"Inspect", &createInspectModule, false},
{"Object", &createObjectModule, true},
#ifndef DISABLE_HTTP
{"HTTP", &createHTTPModule, true},
#endif
Expand Down
1 change: 1 addition & 0 deletions src/optionals/optionals.h
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
#include "sqlite.h"
#include "process.h"
#include "inspect.h"
#include "object/object.h"
#include "unittest/unittest.h"

typedef Value (*BuiltinModule)(DictuVM *vm);
Expand Down
21 changes: 21 additions & 0 deletions tests/object/createFrom.du
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
/**
* createFrom.du
*
* Testing the Object.createFrom method
*/
from UnitTest import UnitTest;

import Object;

class Test {}

class TestObjectCreateFrom < UnitTest {
testObjectCreateFrom() {
this.assertSuccess(Object.createFrom('Test'));
this.assertError(Object.createFrom('Unknown'));

this.assertType(Object.createFrom('Test').unwrap(), 'Test');
}
}

TestObjectCreateFrom().run();
7 changes: 7 additions & 0 deletions tests/object/import.du
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
/**
* import.du
*
* General import file for all the Object module tests
*/

import "createFrom.du";
1 change: 1 addition & 0 deletions tests/runTests.du
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@ import "modules/import.du";
import "imports/import.du";
import "random/import.du";
import "hashlib/import.du";
import "object/import.du";

// If we got here no runtime errors were thrown, therefore all tests passed.
print("All tests passed successfully!");