Skip to content
Browse files

Adds C API no big deal.

  • Loading branch information...
1 parent 44c74c4 commit 01e8f858dbc688e1a8d6d31902ca71800cd3bf88 @pyrated pyrated committed
View
3 configure.ac
@@ -1,5 +1,6 @@
AC_INIT([hkl], [0.0], [], [hkl], [http://github.com/hkl/hkl])
+
AC_CONFIG_MACRO_DIR([m4])
AC_CONFIG_FILES([Makefile src/Makefile])
@@ -9,5 +10,7 @@ AC_PROG_CC
AM_PROG_LEX
AC_PROG_YACC
+AC_CHECK_LIB(dl, dlopen, LIBDL="-ldl")
+
AC_OUTPUT
View
151 examples/joust.hkl
@@ -0,0 +1,151 @@
+include "src/module/math.hkl"
+
+Knight = {
+
+ new = function(name, stamina, weapon, armor, shield)
+
+ return {
+ name: name? "Starry Knight",
+ stamina: stamina? 0,
+ weapon: weapon,
+ armor: armor,
+ shield: shield
+ }
+ end
+}
+
+Weapon = {
+ new = function(name, stamina, hit_chance)
+ return {name: name, stamina: stamina, hit_chance: hit_chance}
+ end
+}
+
+//-- Borrow new function from Weapon
+Armor = { new = Weapon.new }
+Shield = { new = Armor.new }
+
+puts "Joust Tester"
+
+init = function(first_or_second)
+
+ puts "What is the name of the " + first_or_second + " knight?"
+ kname = gets
+ puts "How many stamina points does he have?"
+ kstamina = gets as real
+
+ puts "What is the name of his weapon?"
+ name = gets
+ puts "What is the hit ratio (0 - 100)% of the weapon?"
+ hit_chance = gets as real
+ puts "How many stamina points does it take to wield such a weapon?"
+ weapon1 = Weapon.new(name, gets as real, hit_chance)
+
+ puts "What is the name of his armor?"
+ name = gets
+ puts "What is the hit reduction ratio (0 - 100)% of the armor?"
+ hit_chance = gets as real
+ puts "How many stamina points does it take to wear?"
+ armor1 = Armor.new(name, gets as real, hit_chance)
+
+ puts "What is the name of his shield?"
+ name = gets
+ puts "What is the hit reduction ratio (0 - 100)% of the shield?"
+ hit_chance = gets as real
+ puts "How many stamina points does it take to carry?"
+ shield1 = Armor.new(name, gets as real, hit_chance)
+
+ return Knight.new(kname, kstamina, weapon1, armor1, shield1)
+end
+
+Joust = {}
+Joust.match = function(knight1, knight2)
+
+ Joust.knight1 = knight1
+ Joust.knight2 = knight2
+ Joust.num_rounds = 0
+
+ while Joust.round() end
+end
+
+Joust.round = function()
+
+ k1falls = false
+ k2falls = false
+
+ puts "Round " + Joust.num_rounds
+
+ newstam = knight1.stamina
+ - knight1.weapon.stamina
+ - knight1.armor.stamina
+ - knight1.shield.stamina
+
+ if newstam < 0 newstam = 0 end
+
+ knight1.stamina = newstam
+
+ newstam = knight2.stamina
+ - knight2.weapon.stamina
+ - knight2.armor.stamina
+ - knight2.shield.stamina
+
+ if newstam < 0 newstam = 0 end
+
+ knight2.stamina = newstam
+
+ chance = 0 - knight1.armor.hit_chance
+ - knight1.shield.hit_chance
+ + knight2.weapon.hit_chance
+
+ if chance < 0 chance = 0 end
+
+ puts "\t" + knight1.name + " has a " + chance + "% chance to fall off."
+
+ if Math.random()%100 <= chance
+ k1falls = true
+ end
+
+ chance = 0 - knight2.armor.hit_chance
+ - knight2.shield.hit_chance
+ + knight1.weapon.hit_chance
+
+ if chance < 0 chance = 0 end
+
+ puts "\t" + knight2.name + " has a " + chance + "% chance to fall off."
+
+ if Math.random()%100 <= chance
+ k2falls = true
+ end
+
+ if k1falls
+ puts "\t" + knight2.name + "'s " + knight2.weapon.name + " threw " + knight1.name + "off his horse."
+ end
+
+ if k2falls
+ puts "\t" + knight1.name + "'s " + knight1.weapon.name + " threw " + knight2.name + "off his horse."
+ end
+
+ if k1falls == knight1.stamina
+ puts "\t" + knight1.name + " collapsed from exhaustion!"
+ k1falls = true
+ end
+
+ if k2falls == knight2.stamina
+ puts "\t" + knight2.name + " collapsed from exhaustion!"
+ k2falls = true
+ end
+
+ if k1falls
+ return false
+ end
+
+ if k2falls
+ return false
+ end
+
+ Joust.num_rounds = Joust.num_rounds + 1
+
+ return true
+
+end
+
+Joust.match(init("first"), init("second"))
View
15 examples/math.hkl
@@ -1,14 +1,3 @@
-Math = {}
-Math.PI = 3.1415926
-Math.TAU = Math.PI * 2
+include "src/module/math.hkl"
-Math.abs = function(n)
-
- if n < 0
- return 0-n
- end
-
- return n
-end
-
-puts Math.abs(Math.PI)
+puts Math.pow(3.0, 2.0)
View
45 examples/nprime.hkl
@@ -0,0 +1,45 @@
+sqrt = function(n)
+
+ i = (n / 2) + 1
+ j = (i + (n / i)) / 2
+
+ while j < i
+ i = j
+ j = (i + (n / i)) / 2
+ end
+
+ return i
+end
+
+isprime = function(n)
+
+ sqn = sqrt(n)
+
+ ok = true
+
+ m = 2 while m <= sqn
+
+ if n % m == 0 ok = false break end
+ m = m + 1
+
+ end
+
+ return ok
+
+end
+
+puts "What prime?"
+n = gets as int
+
+j = 2
+prime = 0 while prime < n
+
+ if isprime(j)
+ prime = prime + 1
+ end
+
+ j = j + 1
+
+end
+
+puts "The " + n +"th prime is " + (j - 1)
View
17 examples/tomato.hkl
@@ -0,0 +1,17 @@
+Tomato = {}
+
+Tomato.Color = {red, green, blue, yellow}
+
+Tomato.new = function(color)
+ return {color: color? Tomato.Color.red}
+end
+
+Tomato.throw = function(tmto)
+ puts "Threw a " + tmto.color + " tomato"
+end
+
+tmto = Tomato.new()
+tmto2 = Tomato.new(Tomato.Color.blue)
+
+Tomato.throw(tmto)
+Tomato.throw(tmto2)
View
14 src/Makefile.am
@@ -1,9 +1,10 @@
AM_CFLAGS = -Wall -Wextra -Werror -Wno-unused-parameter -Wno-unused-function -std=gnu99
-AM_LDFLAGS =
AM_YFLAGS = -d -v
AM_LFLAGS =
-bin_PROGRAMS = hkl testbed
+bin_PROGRAMS = hkl math
+
+hkl_LDADD = -ldl
hkl_SOURCES = y.tab.y lex.yy.l hkl_string.c hkl_hash.c hkl_tree.c hkl.c \
hkl_deque.c hklr.c hklr_object.c hklr_expression.c hklr_statement.c \
@@ -34,5 +35,10 @@ statement/hklr_statement_if.c \
statement/hklr_statement_while.c \
linenoise/linenoise.c
-testbed_SOURCES = ${hkl_SOURCES}
-testbed_SOURCES += test/traversal.c test/hash.c
+math_SOURCES = module/math.c
+math_SOURCES += hklr.c hkl_value.c hklr_expression.c
+math_LDADD = -lm
+math_CFLAGS = $(AM_CFLAGS)
+math_CFLAGS += -shared -nostartfiles -fPIC
+
+
View
4 src/expression/hklr_as_string.c
@@ -75,6 +75,10 @@ HklValue* hklr_as_string(HklValue* value)
cast->as.string = hkl_string_new_from_utf8("func");
break;
+ case HKL_TYPE_CFUNC:
+ cast->as.string = hkl_string_new_from_utf8("cfunc");
+ break;
+
default:
assert(false);
break;
View
5 src/hkl.c
@@ -22,6 +22,7 @@ HklList* var_stack;
HklList* closure_stack;
HklList* id_stack;
HklList* pair_stack;
+HklList* interface_stack;
typedef struct yy_buffer_state yy_buffer_state;
extern yy_buffer_state* yy_scan_string(const char*);
@@ -129,6 +130,7 @@ int main(int argc, const char* argv[])
hkl_tree_move_pair(keywords_map, hkl_pair_new_from_utf8("array", NULL));
hkl_tree_move_pair(keywords_map, hkl_pair_new_from_utf8("hash", NULL));
hkl_tree_move_pair(keywords_map, hkl_pair_new_from_utf8("func", NULL));
+ hkl_tree_move_pair(keywords_map, hkl_pair_new_from_utf8("cfunc", NULL));
hkl_tree_move_pair(keywords_map, hkl_pair_new_from_utf8("type", NULL));
hkl_tree_move_pair(keywords_map, hkl_pair_new_from_utf8("true", NULL));
hkl_tree_move_pair(keywords_map, hkl_pair_new_from_utf8("false", NULL));
@@ -140,6 +142,7 @@ int main(int argc, const char* argv[])
hkl_tree_move_pair(keywords_map, hkl_pair_new_from_utf8("typeof", NULL));
hkl_tree_move_pair(keywords_map, hkl_pair_new_from_utf8("function", NULL));
hkl_tree_move_pair(keywords_map, hkl_pair_new_from_utf8("return", NULL));
+ hkl_tree_move_pair(keywords_map, hkl_pair_new_from_utf8("interface", NULL));
// If there is a filename
if (argv[1])
@@ -165,6 +168,7 @@ int main(int argc, const char* argv[])
closure_stack = hkl_list_new();
id_stack = hkl_list_new();
pair_stack = hkl_list_new();
+ interface_stack = hkl_list_new();
// Parse files normally
if (interactive == false)
@@ -205,6 +209,7 @@ int main(int argc, const char* argv[])
hkl_list_free(closure_stack);
hkl_list_free(id_stack);
hkl_list_free(pair_stack);
+ hkl_list_free(interface_stack);
hklr_shutdown();
View
94 src/hklr_expression.c
@@ -1,6 +1,7 @@
#include <stdlib.h>
#include <stdio.h>
#include <assert.h>
+#include <dlfcn.h>
#include "hklr.h"
#include "hkl_alloc.h"
@@ -83,6 +84,11 @@ HklrExpression* hklr_expression_new(HklExpressionType type, ...)
expr->arg[2].list = va_arg(argp, HklList*); // stmts
break;
+ case HKL_EXPR_INTERFACE:
+ expr->arg[0].string = va_arg(argp, HklString*); // file
+ expr->arg[1].list = va_arg(argp, HklList*); // objects
+ break;
+
case HKL_EXPR_UNARY:
expr->arg[0].op = va_arg(argp, HklOperatorType);
expr->arg[1].expression = va_arg(argp, HklrExpression*);
@@ -190,6 +196,64 @@ static bool make_closures(HklPair* pair, void* carrier)
return false;
}
+struct interface_carrier
+{
+ HklHash* hash;
+ void* library;
+};
+
+static bool load_interface(void* pair, void* carrier)
+{
+ HklValue* type = hklr_expression_eval((HklrExpression*) ((HklPair*) pair)->value);
+ HklrObject* object = NULL;
+
+ HklString* symbol_name = hkl_string_new_from_utf8("hklapi_");
+ hkl_string_cat(symbol_name, ((HklPair*) pair)->key);
+
+ void* sym = dlsym(((struct interface_carrier*) carrier)->library, symbol_name->utf8_data);
+
+ hkl_string_free(symbol_name);
+
+ assert(sym != NULL);
+
+ switch (type->as.type)
+ {
+ case HKL_TYPE_REAL:
+ object = hklr_object_new(HKL_TYPE_REAL, HKL_FLAG_NONE, *(double*) sym);
+ break;
+
+ case HKL_TYPE_CFUNC:
+ object = hklr_object_new(HKL_TYPE_CFUNC, HKL_FLAG_NONE, sym);
+ break;
+
+ default:
+ assert(false);
+ break;
+ }
+
+ hkl_hash_insert(((struct interface_carrier*) carrier)->hash, ((HklPair*) pair)->key, object);
+
+ hkl_value_free(type);
+
+ return false;
+}
+
+static bool cfunction_args(void* expr, void* list)
+{
+ HklValue* value = hklr_expression_eval((HklrExpression*) expr);
+
+ if (value->type == HKL_TYPE_REF)
+ {
+ HklValue* temp = value;
+ value = hklr_object_dereference(value->as.object);
+ hkl_value_free(temp);
+ }
+
+ hkl_list_push_back((HklList*) list, value);
+
+ return false;
+}
+
HklValue* hklr_expression_eval(HklrExpression* expr)
{
assert(expr != NULL);
@@ -236,7 +300,7 @@ HklValue* hklr_expression_eval(HklrExpression* expr)
assert(false);
HklListNode* node = list->head;
- while (node && object->type == HKL_TYPE_REF)
+ while (node)
{
HklVariable* var = node->data;
@@ -296,6 +360,19 @@ HklValue* hklr_expression_eval(HklrExpression* expr)
object = pair->value;
}
+ else if (object->type == HKL_TYPE_CFUNC)
+ {
+ // run the function
+ assert(var->type == HKL_VAR_CALL);
+ HklList* args = var->as.list;
+ HklList* call = hkl_list_new();
+ hkl_list_traverse(args, cfunction_args, call);
+
+ HklValue* ret_val = object->as.cfunction(call);
+
+ // need to free the args
+ return ret_val;
+ }
node = node->next;
}
@@ -346,6 +423,21 @@ HklValue* hklr_expression_eval(HklrExpression* expr)
}
break;
+ case HKL_EXPR_INTERFACE:
+ {
+ // Open the interface
+ struct interface_carrier carrier;
+ carrier.hash = hkl_hash_new();
+ carrier.library = dlopen(expr->arg[0].string->utf8_data, RTLD_LAZY);
+
+ assert(carrier.library != NULL);
+
+ hkl_list_traverse(expr->arg[1].list, load_interface, &carrier);
+
+ return hkl_value_new(HKL_TYPE_HASH, carrier.hash);
+ }
+ break;
+
case HKL_EXPR_UNARY:
{
HklValue* value = hklr_expression_eval(expr->arg[1].expression);
View
3 src/hklr_expression.h
@@ -23,7 +23,8 @@ typedef enum HklExpressionType
HKL_EXPR_VAR,
HKL_EXPR_ARRAY,
HKL_EXPR_HASH,
- HKL_EXPR_FUNCTION
+ HKL_EXPR_FUNCTION,
+ HKL_EXPR_INTERFACE
} HklExpressionType;
View
8 src/hklr_object.c
@@ -62,6 +62,10 @@ HklrObject* hklr_object_new(HklType type, HklFlag flags, ...)
object->as.function = va_arg(argp, HklrFunction*);
break;
+ case HKL_TYPE_CFUNC:
+ object->as.cfunction = va_arg(argp, HklValue* (*)(HklList*));
+ break;
+
default:
assert(false);
break;
@@ -109,6 +113,10 @@ HklValue* hklr_object_dereference(HklrObject* object)
case HKL_TYPE_FUNCTION:
return hkl_value_new(HKL_TYPE_FUNCTION, object->as.function);
break;
+
+ case HKL_TYPE_CFUNC:
+ return hkl_value_new(HKL_TYPE_CFUNC, object->as.cfunction);
+ break;
// A composite object reference
case HKL_TYPE_REF:
View
4 src/hklr_object.h
@@ -6,6 +6,7 @@
#include "hkl_string.h"
#include "hkl_hash.h"
#include "hkl_deque.h"
+#include "hkl_list.h"
typedef enum HklColor
{
@@ -53,6 +54,8 @@ typedef enum HklType
@authors Barrett Lewis, Scott LaVigne
@date 10/8/2012
*/
+struct HklRuntime;
+struct HklValue;
typedef struct HklrObject {
// Used for garbage collection
@@ -75,6 +78,7 @@ typedef struct HklrObject {
HklDeque* deque;
HklType type;
struct HklrFunction* function;
+ struct HklValue* (*cfunction)(HklList*);
} as;
View
2 src/lex.yy.l
@@ -34,6 +34,7 @@ HklString* string_buf = NULL;
"assert" return HKL_T_ASSERT;
"load" return HKL_T_LOAD;
"collect" return HKL_T_COLLECT;
+"interface" return HKL_T_INTERFACE;
"include" BEGIN includebuild;
<includebuild>[ \t\r] /* Ignore Whitespace */
@@ -71,6 +72,7 @@ HklString* string_buf = NULL;
"type" return HKL_T_TYPE;
"instance" return HKL_T_INSTANCE;
"func" return HKL_T_FUNC;
+"cfunc" return HKL_T_CFUNC;
"self" return HKL_T_SELF;
View
BIN src/math
Binary file not shown.
View
73 src/module/math.c
@@ -0,0 +1,73 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <math.h>
+
+#include "hkl_value.h"
+#include "hklr_expression.h"
+
+double hklapi_PI = 3.1415926;
+double hklapi_TAU = 2.0*3.1415926;
+
+HklValue* hklapi_random(HklList* args) {
+
+ return hkl_value_new(HKL_TYPE_INT, random());
+}
+
+HklValue* hklapi_sin(HklList* args) {
+
+ HklValue* value = args->head->data;
+ double d = value->as.real;
+ hkl_value_free(value);
+
+ return hkl_value_new(HKL_TYPE_REAL, sin(d));
+}
+
+HklValue* hklapi_cos(HklList* args) {
+
+ HklValue* value = args->head->data;
+ double d = value->as.real;
+ hkl_value_free(value);
+
+ return hkl_value_new(HKL_TYPE_REAL, cos(d));
+}
+
+HklValue* hklapi_tan(HklList* args) {
+
+ HklValue* value = args->head->data;
+ double d = value->as.real;
+ hkl_value_free(value);
+
+ return hkl_value_new(HKL_TYPE_REAL, tan(d));
+}
+
+HklValue* hklapi_log(HklList* args) {
+
+ HklValue* value = args->head->data;
+ double d = value->as.real;
+ hkl_value_free(value);
+
+ return hkl_value_new(HKL_TYPE_REAL, log(d));
+}
+
+HklValue* hklapi_log10(HklList* args) {
+
+ HklValue* value = args->head->data;
+ double d = value->as.real;
+ hkl_value_free(value);
+
+ return hkl_value_new(HKL_TYPE_REAL, log10(d));
+}
+
+HklValue* hklapi_pow(HklList* args) {
+
+ HklValue* value = args->head->data;
+ double base = value->as.real;
+ hkl_value_free(value);
+
+
+ value = args->head->next->data;
+ double e = value->as.real;
+ hkl_value_free(value);
+
+ return hkl_value_new(HKL_TYPE_REAL, pow(base, e));
+}
View
12 src/module/math.hkl
@@ -0,0 +1,12 @@
+Math = interface "src/math"
+
+ random: cfunc
+ PI: real
+ sin: cfunc
+ cos: cfunc
+ tan: cfunc
+ log: cfunc
+ log10: cfunc
+ pow: cfunc
+
+end
View
99 src/y.tab.y
@@ -21,6 +21,7 @@
extern HklList* closure_stack;
extern HklList* pair_stack;
extern HklList* id_stack;
+ extern HklList* interface_stack;
void reduce_stat(HklrStatement* stmt)
{
@@ -69,6 +70,7 @@
%token HKL_T_LOAD "load"
%token HKL_T_ASSERT "assert"
%token HKL_T_COLLECT "collect"
+%token HKL_T_INTERFACE "interface"
%token HKL_T_CLASS "class"
%token HKL_T_FUNCTION "function"
@@ -81,6 +83,7 @@
%token HKL_T_TYPE "type"
%token HKL_T_INSTANCE "instance"
%token HKL_T_FUNC "func"
+%token HKL_T_CFUNC "cfunc"
%token HKL_T_SWITCH "switch"
%token HKL_T_CASE "case"
%token HKL_T_DEFAULT "default"
@@ -155,7 +158,7 @@
%token <string> HKL_T_STRING_CONSTANT "string literal"
%type <statement> nobr_stat
-%type <expression> expr nobr_variable nobr_prefix nobr_call
+%type <expression> type expr nobr_variable nobr_prefix nobr_call
%type <list> args
%type <pair> pair
@@ -306,34 +309,7 @@ expr:
{
$$ = hklr_expression_new(HKL_EXPR_STRING, $1);
}
- | HKL_T_INT
- {
- $$ = hklr_expression_new(HKL_EXPR_TYPE, HKL_TYPE_INT);
- }
- | HKL_T_REAL
- {
- $$ = hklr_expression_new(HKL_EXPR_TYPE, HKL_TYPE_REAL);
- }
- | HKL_T_STRING
- {
- $$ = hklr_expression_new(HKL_EXPR_TYPE, HKL_TYPE_STRING);
- }
- | HKL_T_HASH
- {
- $$ = hklr_expression_new(HKL_EXPR_TYPE, HKL_TYPE_HASH);
- }
- | HKL_T_ARRAY
- {
- $$ = hklr_expression_new(HKL_EXPR_TYPE, HKL_TYPE_ARRAY);
- }
- | HKL_T_FUNC
- {
- $$ = hklr_expression_new(HKL_EXPR_TYPE, HKL_TYPE_FUNCTION);
- }
- | HKL_T_TYPE
- {
- $$ = hklr_expression_new(HKL_EXPR_TYPE, HKL_TYPE_TYPE);
- }
+ | type
| HKL_T_FUNCTION
{
hkl_list_push_back(stmt_stack, hkl_list_new());
@@ -442,7 +418,6 @@ expr:
{
$$ = hklr_expression_new(HKL_EXPR_BINARY, $1, HKL_OP_AS, $3);
}
-
| expr HKL_T_BITWISE_AND expr
{
$$ = hklr_expression_new(HKL_EXPR_BINARY, $1, HKL_OP_BITWISE_AND, $3);
@@ -459,8 +434,6 @@ expr:
{
$$ = hklr_expression_new(HKL_EXPR_UNARY, HKL_OP_BITWISE_NOT, $2);
}
-
-
| HKL_T_MINUS expr %prec UNARY_OPS
{
$$ = hklr_expression_new(HKL_EXPR_UNARY, HKL_OP_UNARY_MINUS, $2);
@@ -473,6 +446,68 @@ expr:
{
$$ = hklr_expression_new(HKL_EXPR_UNARY, HKL_OP_TYPEOF, $2);
}
+ |
+ HKL_T_INTERFACE HKL_T_STRING_CONSTANT
+ {
+ hkl_list_push_back(interface_stack, hkl_list_new());
+ HKLR.scope_level++;
+ }
+ interface_list HKL_T_END
+ {
+ HKLR.scope_level--;
+ $$ = hklr_expression_new(HKL_EXPR_INTERFACE, $2, hkl_list_pop_back(interface_stack));
+ }
+ ;
+
+type:
+ HKL_T_INT
+ {
+ $$ = hklr_expression_new(HKL_EXPR_TYPE, HKL_TYPE_INT);
+ }
+ | HKL_T_REAL
+ {
+ $$ = hklr_expression_new(HKL_EXPR_TYPE, HKL_TYPE_REAL);
+ }
+ | HKL_T_STRING
+ {
+ $$ = hklr_expression_new(HKL_EXPR_TYPE, HKL_TYPE_STRING);
+ }
+ | HKL_T_HASH
+ {
+ $$ = hklr_expression_new(HKL_EXPR_TYPE, HKL_TYPE_HASH);
+ }
+ | HKL_T_ARRAY
+ {
+ $$ = hklr_expression_new(HKL_EXPR_TYPE, HKL_TYPE_ARRAY);
+ }
+ | HKL_T_FUNC
+ {
+ $$ = hklr_expression_new(HKL_EXPR_TYPE, HKL_TYPE_FUNCTION);
+ }
+ | HKL_T_CFUNC
+ {
+ $$ = hklr_expression_new(HKL_EXPR_TYPE, HKL_TYPE_CFUNC);
+ }
+ | HKL_T_TYPE
+ {
+ $$ = hklr_expression_new(HKL_EXPR_TYPE, HKL_TYPE_TYPE);
+ }
+ ;
+
+interface_list:
+ interface
+ | interface_list interface
+ ;
+
+interface:
+ HKL_T_STRING_CONSTANT HKL_T_COLON type
+ {
+ hkl_list_push_back((HklList*) interface_stack->tail->data, hkl_pair_new_from_data($1, $3));
+ }
+ | HKL_T_ID HKL_T_COLON type
+ {
+ hkl_list_push_back((HklList*) interface_stack->tail->data, hkl_pair_new_from_data($1, $3));
+ }
;
expr_list:

0 comments on commit 01e8f85

Please sign in to comment.
Something went wrong with that request. Please try again.