feat: add Alexander Roper to AUTHORS and expand embedding API documentation
- Add Alexander Roper to AUTHORS file with newline fix for Starbeamrainbowlabs entry - Replace placeholder embedding API docs with full guide covering static/dynamic linking and source inclusion - Update codebase line count from 5,000 to 7,000 lines in README and index - Fix relative documentation links to absolute URLs in README - Add CSS styling for preprocessor directive syntax highlighting - Update Xcode project file references and CopyFiles build phase UUID - Adjust delta_blue benchmark expected value from 7032700 to 14065400 - Improve markdown header detection regex in generate_docs.py to avoid matching #include - Refactor metrics.py to exclude curly brace lines from code line counting - Add TEST_HEADERS dependency to test object compilation in wren.mk - Remove NULL parameter from runFile call in main.c - Refactor vm.c to support WrenBindForeignClassFn callback and rename externalBindForeign to bindMethodFn - Update vm.h to remove bindForeign parameter documentation and adjust runFile signature
This commit is contained in:
@@ -0,0 +1,87 @@
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "foreign_class.h"
|
||||
|
||||
static void counterAllocate(WrenVM* vm)
|
||||
{
|
||||
double* value = (double*)wrenAllocateForeign(vm, sizeof(double));
|
||||
*value = 0;
|
||||
}
|
||||
|
||||
static void counterIncrement(WrenVM* vm)
|
||||
{
|
||||
double* value = (double*)wrenGetArgumentForeign(vm, 0);
|
||||
double increment = wrenGetArgumentDouble(vm, 1);
|
||||
|
||||
*value += increment;
|
||||
}
|
||||
|
||||
static void counterValue(WrenVM* vm)
|
||||
{
|
||||
double value = *(double*)wrenGetArgumentForeign(vm, 0);
|
||||
wrenReturnDouble(vm, value);
|
||||
}
|
||||
|
||||
static void pointAllocate(WrenVM* vm)
|
||||
{
|
||||
double* coordinates = (double*)wrenAllocateForeign(vm, sizeof(double[3]));
|
||||
|
||||
// This gets called by both constructors, so sniff the argument count to see
|
||||
// which one was invoked.
|
||||
if (wrenGetArgumentCount(vm) == 1)
|
||||
{
|
||||
coordinates[0] = 0.0;
|
||||
coordinates[1] = 0.0;
|
||||
coordinates[2] = 0.0;
|
||||
}
|
||||
else
|
||||
{
|
||||
coordinates[0] = wrenGetArgumentDouble(vm, 1);
|
||||
coordinates[1] = wrenGetArgumentDouble(vm, 2);
|
||||
coordinates[2] = wrenGetArgumentDouble(vm, 3);
|
||||
}
|
||||
}
|
||||
|
||||
static void pointTranslate(WrenVM* vm)
|
||||
{
|
||||
double* coordinates = (double*)wrenGetArgumentForeign(vm, 0);
|
||||
coordinates[0] += wrenGetArgumentDouble(vm, 1);
|
||||
coordinates[1] += wrenGetArgumentDouble(vm, 2);
|
||||
coordinates[2] += wrenGetArgumentDouble(vm, 3);
|
||||
}
|
||||
|
||||
static void pointToString(WrenVM* vm)
|
||||
{
|
||||
double* coordinates = (double*)wrenGetArgumentForeign(vm, 0);
|
||||
char result[100];
|
||||
sprintf(result, "(%g, %g, %g)",
|
||||
coordinates[0], coordinates[1], coordinates[2]);
|
||||
wrenReturnString(vm, result, (int)strlen(result));
|
||||
}
|
||||
|
||||
WrenForeignMethodFn foreignClassBindMethod(const char* signature)
|
||||
{
|
||||
if (strcmp(signature, "Counter.increment(_)") == 0) return counterIncrement;
|
||||
if (strcmp(signature, "Counter.value") == 0) return counterValue;
|
||||
if (strcmp(signature, "Point.translate(_,_,_)") == 0) return pointTranslate;
|
||||
if (strcmp(signature, "Point.toString") == 0) return pointToString;
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void foreignClassBindClass(
|
||||
const char* className, WrenForeignClassMethods* methods)
|
||||
{
|
||||
if (strcmp(className, "Counter") == 0)
|
||||
{
|
||||
methods->allocate = counterAllocate;
|
||||
return;
|
||||
}
|
||||
|
||||
if (strcmp(className, "Point") == 0)
|
||||
{
|
||||
methods->allocate = pointAllocate;
|
||||
return;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,5 @@
|
||||
#include "wren.h"
|
||||
|
||||
WrenForeignMethodFn foreignClassBindMethod(const char* signature);
|
||||
void foreignClassBindClass(
|
||||
const char* className, WrenForeignClassMethods* methods);
|
||||
@@ -0,0 +1,48 @@
|
||||
// Class with a default constructor.
|
||||
foreign class Counter {
|
||||
foreign increment(amount)
|
||||
foreign value
|
||||
}
|
||||
|
||||
var counter = Counter.new()
|
||||
IO.print(counter.value) // expect: 0
|
||||
counter.increment(3.1)
|
||||
IO.print(counter.value) // expect: 3.1
|
||||
counter.increment(1.2)
|
||||
IO.print(counter.value) // expect: 4.3
|
||||
|
||||
// Foreign classes can inherit a class as long as it has no fields.
|
||||
class PointBase {
|
||||
inherited() {
|
||||
IO.print("inherited method")
|
||||
}
|
||||
}
|
||||
|
||||
// Class with non-default constructor.
|
||||
foreign class Point is PointBase {
|
||||
construct new() {
|
||||
IO.print("default")
|
||||
}
|
||||
|
||||
construct new(x, y, z) {
|
||||
IO.print(x, ", ", y, ", ", z)
|
||||
}
|
||||
|
||||
foreign translate(x, y, z)
|
||||
foreign toString
|
||||
}
|
||||
|
||||
var p = Point.new(1, 2, 3) // expect: 1, 2, 3
|
||||
IO.print(p) // expect: (1, 2, 3)
|
||||
p.translate(3, 4, 5)
|
||||
IO.print(p) // expect: (4, 6, 8)
|
||||
|
||||
p = Point.new() // expect: default
|
||||
IO.print(p) // expect: (0, 0, 0)
|
||||
|
||||
p.inherited() // expect: inherited method
|
||||
|
||||
var error = Fiber.new {
|
||||
class Subclass is Point {}
|
||||
}.try()
|
||||
IO.print(error) // expect: Class 'Subclass' cannot inherit from foreign class 'Point'.
|
||||
@@ -1,3 +0,0 @@
|
||||
#include "wren.h"
|
||||
|
||||
WrenForeignMethodFn getValueBindForeign(const char* signature);
|
||||
+30
-15
@@ -5,18 +5,23 @@
|
||||
#include "vm.h"
|
||||
#include "wren.h"
|
||||
|
||||
#include "get_value/get_value.h"
|
||||
#include "return_bool/return_bool.h"
|
||||
#include "return_double/return_double.h"
|
||||
#include "return_null/return_null.h"
|
||||
#include "foreign_class.h"
|
||||
#include "returns.h"
|
||||
#include "value.h"
|
||||
|
||||
#define REGISTER_TEST(name, camelCase) \
|
||||
if (strcmp(testName, #name) == 0) return camelCase##BindForeign(fullName)
|
||||
#define REGISTER_METHOD(name, camelCase) \
|
||||
if (strcmp(testName, #name) == 0) return camelCase##BindMethod(fullName)
|
||||
|
||||
#define REGISTER_CLASS(name, camelCase) \
|
||||
if (strcmp(testName, #name) == 0) \
|
||||
{ \
|
||||
camelCase##BindClass(className, &methods); \
|
||||
}
|
||||
|
||||
// The name of the currently executing API test.
|
||||
const char* testName;
|
||||
|
||||
static WrenForeignMethodFn bindForeign(
|
||||
static WrenForeignMethodFn bindForeignMethod(
|
||||
WrenVM* vm, const char* module, const char* className,
|
||||
bool isStatic, const char* signature)
|
||||
{
|
||||
@@ -31,10 +36,9 @@ static WrenForeignMethodFn bindForeign(
|
||||
strcat(fullName, ".");
|
||||
strcat(fullName, signature);
|
||||
|
||||
REGISTER_TEST(get_value, getValue);
|
||||
REGISTER_TEST(return_bool, returnBool);
|
||||
REGISTER_TEST(return_double, returnDouble);
|
||||
REGISTER_TEST(return_null, returnNull);
|
||||
REGISTER_METHOD(foreign_class, foreignClass);
|
||||
REGISTER_METHOD(returns, returns);
|
||||
REGISTER_METHOD(value, value);
|
||||
|
||||
fprintf(stderr,
|
||||
"Unknown foreign method '%s' for test '%s'\n", fullName, testName);
|
||||
@@ -42,6 +46,18 @@ static WrenForeignMethodFn bindForeign(
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static WrenForeignClassMethods bindForeignClass(
|
||||
WrenVM* vm, const char* module, const char* className)
|
||||
{
|
||||
WrenForeignClassMethods methods = { NULL, NULL };
|
||||
if (strcmp(module, "main") != 0) return methods;
|
||||
|
||||
REGISTER_CLASS(foreign_class, foreignClass);
|
||||
|
||||
return methods;
|
||||
}
|
||||
|
||||
|
||||
int main(int argc, const char* argv[])
|
||||
{
|
||||
if (argc != 2)
|
||||
@@ -52,14 +68,13 @@ int main(int argc, const char* argv[])
|
||||
|
||||
testName = argv[1];
|
||||
|
||||
// The test script is at "test/api/<test>/<test>.wren".
|
||||
// The test script is at "test/api/<test>.wren".
|
||||
char testPath[256];
|
||||
strcpy(testPath, "test/api/");
|
||||
strcat(testPath, testName);
|
||||
strcat(testPath, "/");
|
||||
strcat(testPath, testName);
|
||||
strcat(testPath, ".wren");
|
||||
|
||||
runFile(testPath, bindForeign);
|
||||
setForeignCallbacks(bindForeignMethod, bindForeignClass);
|
||||
runFile(testPath);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -1,21 +0,0 @@
|
||||
#include <string.h>
|
||||
|
||||
#include "return_bool.h"
|
||||
|
||||
static void returnTrue(WrenVM* vm)
|
||||
{
|
||||
wrenReturnBool(vm, true);
|
||||
}
|
||||
|
||||
static void returnFalse(WrenVM* vm)
|
||||
{
|
||||
wrenReturnBool(vm, false);
|
||||
}
|
||||
|
||||
WrenForeignMethodFn returnBoolBindForeign(const char* signature)
|
||||
{
|
||||
if (strcmp(signature, "static Api.returnTrue") == 0) return returnTrue;
|
||||
if (strcmp(signature, "static Api.returnFalse") == 0) return returnFalse;
|
||||
|
||||
return NULL;
|
||||
}
|
||||
@@ -1,3 +0,0 @@
|
||||
#include "wren.h"
|
||||
|
||||
WrenForeignMethodFn returnBoolBindForeign(const char* signature);
|
||||
@@ -1,7 +0,0 @@
|
||||
class Api {
|
||||
foreign static returnTrue
|
||||
foreign static returnFalse
|
||||
}
|
||||
|
||||
IO.print(Api.returnTrue) // expect: true
|
||||
IO.print(Api.returnFalse) // expect: false
|
||||
@@ -1,21 +0,0 @@
|
||||
#include <string.h>
|
||||
|
||||
#include "return_double.h"
|
||||
|
||||
static void returnInt(WrenVM* vm)
|
||||
{
|
||||
wrenReturnDouble(vm, 123456);
|
||||
}
|
||||
|
||||
static void returnFloat(WrenVM* vm)
|
||||
{
|
||||
wrenReturnDouble(vm, 123.456);
|
||||
}
|
||||
|
||||
WrenForeignMethodFn returnDoubleBindForeign(const char* signature)
|
||||
{
|
||||
if (strcmp(signature, "static Api.returnInt") == 0) return returnInt;
|
||||
if (strcmp(signature, "static Api.returnFloat") == 0) return returnFloat;
|
||||
|
||||
return NULL;
|
||||
}
|
||||
@@ -1,3 +0,0 @@
|
||||
#include "wren.h"
|
||||
|
||||
WrenForeignMethodFn returnDoubleBindForeign(const char* signature);
|
||||
@@ -1,7 +0,0 @@
|
||||
class Api {
|
||||
foreign static returnInt
|
||||
foreign static returnFloat
|
||||
}
|
||||
|
||||
IO.print(Api.returnInt) // expect: 123456
|
||||
IO.print(Api.returnFloat) // expect: 123.456
|
||||
@@ -1,15 +0,0 @@
|
||||
#include <string.h>
|
||||
|
||||
#include "return_null.h"
|
||||
|
||||
static void implicitNull(WrenVM* vm)
|
||||
{
|
||||
// Do nothing.
|
||||
}
|
||||
|
||||
WrenForeignMethodFn returnNullBindForeign(const char* signature)
|
||||
{
|
||||
if (strcmp(signature, "static Api.implicitNull") == 0) return implicitNull;
|
||||
|
||||
return NULL;
|
||||
}
|
||||
@@ -1,3 +0,0 @@
|
||||
#include "wren.h"
|
||||
|
||||
WrenForeignMethodFn returnNullBindForeign(const char* signature);
|
||||
@@ -1,5 +0,0 @@
|
||||
class Api {
|
||||
foreign static implicitNull
|
||||
}
|
||||
|
||||
IO.print(Api.implicitNull == null) // expect: true
|
||||
@@ -0,0 +1,39 @@
|
||||
#include <string.h>
|
||||
|
||||
#include "returns.h"
|
||||
|
||||
static void implicitNull(WrenVM* vm)
|
||||
{
|
||||
// Do nothing.
|
||||
}
|
||||
|
||||
static void returnInt(WrenVM* vm)
|
||||
{
|
||||
wrenReturnDouble(vm, 123456);
|
||||
}
|
||||
|
||||
static void returnFloat(WrenVM* vm)
|
||||
{
|
||||
wrenReturnDouble(vm, 123.456);
|
||||
}
|
||||
|
||||
static void returnTrue(WrenVM* vm)
|
||||
{
|
||||
wrenReturnBool(vm, true);
|
||||
}
|
||||
|
||||
static void returnFalse(WrenVM* vm)
|
||||
{
|
||||
wrenReturnBool(vm, false);
|
||||
}
|
||||
|
||||
WrenForeignMethodFn returnsBindMethod(const char* signature)
|
||||
{
|
||||
if (strcmp(signature, "static Api.implicitNull") == 0) return implicitNull;
|
||||
if (strcmp(signature, "static Api.returnInt") == 0) return returnInt;
|
||||
if (strcmp(signature, "static Api.returnFloat") == 0) return returnFloat;
|
||||
if (strcmp(signature, "static Api.returnTrue") == 0) return returnTrue;
|
||||
if (strcmp(signature, "static Api.returnFalse") == 0) return returnFalse;
|
||||
|
||||
return NULL;
|
||||
}
|
||||
@@ -0,0 +1,3 @@
|
||||
#include "wren.h"
|
||||
|
||||
WrenForeignMethodFn returnsBindMethod(const char* signature);
|
||||
@@ -0,0 +1,17 @@
|
||||
class Api {
|
||||
foreign static implicitNull
|
||||
|
||||
foreign static returnInt
|
||||
foreign static returnFloat
|
||||
|
||||
foreign static returnTrue
|
||||
foreign static returnFalse
|
||||
}
|
||||
|
||||
IO.print(Api.implicitNull == null) // expect: true
|
||||
|
||||
IO.print(Api.returnInt) // expect: 123456
|
||||
IO.print(Api.returnFloat) // expect: 123.456
|
||||
|
||||
IO.print(Api.returnTrue) // expect: true
|
||||
IO.print(Api.returnFalse) // expect: false
|
||||
@@ -1,6 +1,6 @@
|
||||
#include <string.h>
|
||||
|
||||
#include "get_value.h"
|
||||
#include "value.h"
|
||||
|
||||
static WrenValue* value;
|
||||
|
||||
@@ -15,7 +15,7 @@ static void getValue(WrenVM* vm)
|
||||
wrenReleaseValue(vm, value);
|
||||
}
|
||||
|
||||
WrenForeignMethodFn getValueBindForeign(const char* signature)
|
||||
WrenForeignMethodFn valueBindMethod(const char* signature)
|
||||
{
|
||||
if (strcmp(signature, "static Api.value=(_)") == 0) return setValue;
|
||||
if (strcmp(signature, "static Api.value") == 0) return getValue;
|
||||
@@ -0,0 +1,3 @@
|
||||
#include "wren.h"
|
||||
|
||||
WrenForeignMethodFn valueBindMethod(const char* signature);
|
||||
@@ -626,7 +626,7 @@ planner = None
|
||||
def delta_blue():
|
||||
global total
|
||||
start = time.clock()
|
||||
for i in range(20):
|
||||
for i in range(40):
|
||||
chain_test(100)
|
||||
projection_test(100)
|
||||
print(total)
|
||||
|
||||
@@ -34,17 +34,6 @@
|
||||
// I've kept it this way to avoid deviating too much from the original
|
||||
// implementation.
|
||||
|
||||
// TODO: Support forward declarations of globals.
|
||||
var REQUIRED = null
|
||||
var STRONG_REFERRED = null
|
||||
var PREFERRED = null
|
||||
var STRONG_DEFAULT = null
|
||||
var NORMAL = null
|
||||
var WEAK_DEFAULT = null
|
||||
var WEAKEST = null
|
||||
|
||||
var ORDERED = null
|
||||
|
||||
// Strengths are used to measure the relative importance of constraints.
|
||||
// New strengths may be inserted in the strength hierarchy without
|
||||
// disrupting current constraints. Strengths cannot be created outside
|
||||
@@ -67,15 +56,15 @@ class Strength {
|
||||
}
|
||||
|
||||
// Compile time computed constants.
|
||||
REQUIRED = Strength.new(0, "required")
|
||||
STRONG_REFERRED = Strength.new(1, "strongPreferred")
|
||||
PREFERRED = Strength.new(2, "preferred")
|
||||
STRONG_DEFAULT = Strength.new(3, "strongDefault")
|
||||
NORMAL = Strength.new(4, "normal")
|
||||
WEAK_DEFAULT = Strength.new(5, "weakDefault")
|
||||
WEAKEST = Strength.new(6, "weakest")
|
||||
var REQUIRED = Strength.new(0, "required")
|
||||
var STRONG_REFERRED = Strength.new(1, "strongPreferred")
|
||||
var PREFERRED = Strength.new(2, "preferred")
|
||||
var STRONG_DEFAULT = Strength.new(3, "strongDefault")
|
||||
var NORMAL = Strength.new(4, "normal")
|
||||
var WEAK_DEFAULT = Strength.new(5, "weakDefault")
|
||||
var WEAKEST = Strength.new(6, "weakest")
|
||||
|
||||
ORDERED = [
|
||||
var ORDERED = [
|
||||
WEAKEST, WEAK_DEFAULT, NORMAL, STRONG_DEFAULT, PREFERRED, STRONG_REFERRED
|
||||
]
|
||||
|
||||
@@ -701,7 +690,7 @@ var projectionTest = Fn.new {|n|
|
||||
}
|
||||
|
||||
var start = IO.clock
|
||||
for (i in 0...20) {
|
||||
for (i in 0...40) {
|
||||
chainTest.call(100)
|
||||
projectionTest.call(100)
|
||||
}
|
||||
|
||||
@@ -0,0 +1,9 @@
|
||||
foreign class Foo {
|
||||
bar {
|
||||
// Can't read a field.
|
||||
IO.print(_bar) // expect error
|
||||
|
||||
// Or write one.
|
||||
_bar = "value" // expect error
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
class Foo {
|
||||
method() {
|
||||
_field = "value"
|
||||
}
|
||||
}
|
||||
|
||||
foreign class Bar is Foo {} // expect runtime error: Foreign class 'Bar' may not inherit from a class with fields.
|
||||
@@ -0,0 +1,2 @@
|
||||
// Missing "class".
|
||||
foreign blah A {} // expect error
|
||||
@@ -1 +1 @@
|
||||
class Subclass is Class {} // expect runtime error: Subclass cannot inherit from Class.
|
||||
class Subclass is Class {} // expect runtime error: Class 'Subclass' cannot inherit from built-in class 'Class'.
|
||||
|
||||
@@ -5,4 +5,4 @@ var ClosureType
|
||||
ClosureType = Fn.new { IO.print(a) }.type
|
||||
}
|
||||
|
||||
class Subclass is ClosureType {} // expect runtime error: Subclass cannot inherit from Fn.
|
||||
class Subclass is ClosureType {} // expect runtime error: Class 'Subclass' cannot inherit from built-in class 'Fn'.
|
||||
|
||||
@@ -1 +1 @@
|
||||
class Subclass is Fiber {} // expect runtime error: Subclass cannot inherit from Fiber.
|
||||
class Subclass is Fiber {} // expect runtime error: Class 'Subclass' cannot inherit from built-in class 'Fiber'.
|
||||
|
||||
@@ -1 +1 @@
|
||||
class Subclass is Fn {} // expect runtime error: Subclass cannot inherit from Fn.
|
||||
class Subclass is Fn {} // expect runtime error: Class 'Subclass' cannot inherit from built-in class 'Fn'.
|
||||
|
||||
@@ -1 +1 @@
|
||||
class Subclass is List {} // expect runtime error: Subclass cannot inherit from List.
|
||||
class Subclass is List {} // expect runtime error: Class 'Subclass' cannot inherit from built-in class 'List'.
|
||||
|
||||
@@ -1 +1 @@
|
||||
class Subclass is Map {} // expect runtime error: Subclass cannot inherit from Map.
|
||||
class Subclass is Map {} // expect runtime error: Class 'Subclass' cannot inherit from built-in class 'Map'.
|
||||
|
||||
@@ -1 +1 @@
|
||||
class Foo is 123 {} // expect runtime error: Must inherit from a class.
|
||||
class Foo is 123 {} // expect runtime error: Class 'Foo' cannot inherit from a non-class object.
|
||||
|
||||
@@ -1 +1 @@
|
||||
class Subclass is Range {} // expect runtime error: Subclass cannot inherit from Range.
|
||||
class Subclass is Range {} // expect runtime error: Class 'Subclass' cannot inherit from built-in class 'Range'.
|
||||
|
||||
@@ -1 +1 @@
|
||||
class Subclass is String {} // expect runtime error: Subclass cannot inherit from String.
|
||||
class Subclass is String {} // expect runtime error: Class 'Subclass' cannot inherit from built-in class 'String'.
|
||||
|
||||
@@ -22,5 +22,3 @@ bar.method(1, 2) // expect: bar
|
||||
bar.method(1, 2, 3) // expect: foo
|
||||
bar.method(1, 2, 3, 4) // expect: bar
|
||||
bar.override // expect: bar
|
||||
|
||||
// TODO: Prevent extending built-in types.
|
||||
|
||||
@@ -6,5 +6,4 @@ IO.print(-0) // expect: -0
|
||||
IO.print(123.456) // expect: 123.456
|
||||
IO.print(-0.001) // expect: -0.001
|
||||
|
||||
// TODO: Scientific notation?
|
||||
// TODO: Literals at and beyond numeric limits.
|
||||
|
||||
@@ -0,0 +1 @@
|
||||
var x = 1.2e // expect error
|
||||
@@ -0,0 +1 @@
|
||||
var x = 1.2e3.4 // expect error
|
||||
@@ -0,0 +1,9 @@
|
||||
var x = 2.55e2
|
||||
|
||||
IO.print(x) // expect: 255
|
||||
IO.print(x + 1) // expect: 256
|
||||
IO.print(x == 255) // expect: true
|
||||
IO.print(2.55e-2 is Num) // expect: true
|
||||
IO.print(x is Num) // expect: true
|
||||
IO.print(-2.55e2) // expect: -255
|
||||
IO.print(-25500e-2) // expect: -255
|
||||
@@ -0,0 +1 @@
|
||||
var x = 1e // expect error
|
||||
@@ -0,0 +1 @@
|
||||
var x = 1.e // expect runtime error: Num does not implement 'e'.
|
||||
@@ -0,0 +1 @@
|
||||
var x = 1.2e3e4 // expect error
|
||||
Reference in New Issue
Block a user