diff --git a/.gitignore b/.gitignore old mode 100644 new mode 100755 diff --git a/assert-gooder.lua b/assert-gooder.lua index f874795..706488c 100644 --- a/assert-gooder.lua +++ b/assert-gooder.lua @@ -27,10 +27,33 @@ local CONSTANT_VALUE_TOKEN = { NIL = function() return nil end } +local function table_indexing (t, k) return t[k] end + +local function safe_index (t, index) + assert(type(t) == 'table') + + -- Attempt rawget first + local value = rawget(t, index) + if value ~= nil then return value end + + local mt = debug.getmetatable(t) + if mt.__index then + -- If weird indexing, use pcall + local success, value = pcall(table_indexing, t, index) + if success then return value end + return nil + else + -- Then attempt normal indexing, if no weirdness + return t[index] + end +end + local function get_variable (var_name, info) - -- - assert(type(var_name) == 'string') - assert(type(info) == 'table') + -- Assertions + assert(type(var_name) == 'string') + assert(type(info) == 'table') + assert(type(info.func) == 'function') + assert(type(info.locals) == 'table') -- Local if info.locals[var_name] then @@ -47,7 +70,7 @@ local function get_variable (var_name, info) until not name -- Global - local env = getfenv(info.func)[var_name] + local env = safe_index(getfenv(info.func), var_name) return env, 'global' end @@ -251,25 +274,27 @@ local function for_each_node_in_ast (ast, func) return func(ast) end -local CONSTANT_OP = {} +local CONSTANT_BINOP = {} +local CONSTANT_UNOP = {} -function CONSTANT_OP.DOT (node) return node[1].value[ node[2].value ] end -- TODO -function CONSTANT_OP.AND (node) return node[1].value and node[2].value end -function CONSTANT_OP.OR (node) return node[1].value or node[2].value end -function CONSTANT_OP.PLUS (node) return node[1].value + node[2].value end -function CONSTANT_OP.MINUS (node) return node[1].value - node[2].value end -function CONSTANT_OP.TIMES (node) return node[1].value * node[2].value end -function CONSTANT_OP.DIVIDE (node) return node[1].value / node[2].value end -function CONSTANT_OP.MODULO (node) return node[1].value % node[2].value end -function CONSTANT_OP.CARET (node) return node[1].value ^ node[2].value end -function CONSTANT_OP.HASHTAG (node) return #node[1].value end -function CONSTANT_OP.EQ (node) return node[1].value == node[2].value end -function CONSTANT_OP.NEQ (node) return node[1].value ~= node[2].value end -function CONSTANT_OP.LEQ (node) return node[1].value <= node[2].value end -function CONSTANT_OP.GEQ (node) return node[1].value >= node[2].value end -function CONSTANT_OP.LE (node) return node[1].value < node[2].value end -function CONSTANT_OP.GT (node) return node[1].value > node[2].value end -function CONSTANT_OP.CONCAT (node) return node[1].value .. node[2].value end +function CONSTANT_BINOP.DOT (node) return node[1].value[ node[2].value ] end -- TODO +function CONSTANT_BINOP.AND (node) return node[1].value and node[2].value end +function CONSTANT_BINOP.OR (node) return node[1].value or node[2].value end +function CONSTANT_BINOP.PLUS (node) return node[1].value + node[2].value end +function CONSTANT_BINOP.MINUS (node) return node[1].value - node[2].value end +function CONSTANT_BINOP.TIMES (node) return node[1].value * node[2].value end +function CONSTANT_BINOP.DIVIDE (node) return node[1].value / node[2].value end +function CONSTANT_BINOP.MODULO (node) return node[1].value % node[2].value end +function CONSTANT_BINOP.CARET (node) return node[1].value ^ node[2].value end +function CONSTANT_BINOP.EQ (node) return node[1].value == node[2].value end +function CONSTANT_BINOP.NEQ (node) return node[1].value ~= node[2].value end +function CONSTANT_BINOP.LEQ (node) return node[1].value <= node[2].value end +function CONSTANT_BINOP.GEQ (node) return node[1].value >= node[2].value end +function CONSTANT_BINOP.LE (node) return node[1].value < node[2].value end +function CONSTANT_BINOP.GT (node) return node[1].value > node[2].value end +function CONSTANT_BINOP.CONCAT (node) return node[1].value .. node[2].value end + +function CONSTANT_UNOP.HASHTAG (node) return #node[1].value end local function populate_ast_with_semantics (ast, info) assert(type(ast) == 'table') @@ -281,15 +306,21 @@ local function populate_ast_with_semantics (ast, info) end end) + --print 'Semantics!' return for_each_node_in_ast(ast, function(node) + --print(require'pretty'(node)) if node.exp == 'IDENTIFIER' then node.value, node.scope, node.function_local = get_variable(node.text, info) elseif CONSTANT_VALUE_TOKEN[node.exp] then node.value = CONSTANT_VALUE_TOKEN[node.exp](node.text) node.is_constant = true - elseif node.exp == 'OP' and CONSTANT_OP[node.binop] and node[1].value and node[2] and node[2].value then + elseif node.exp == 'OP' and CONSTANT_UNOP[node.binop] and node[1].value then + assert(node[1].value) + node.value = CONSTANT_UNOP[node.binop](node) + node.is_constant = node[1].is_constant + elseif node.exp == 'OP' and CONSTANT_BINOP[node.binop] and node[1].value and node[2] and node[2].value then assert(node[1].value and (not node[2] or node[2].value)) - node.value = CONSTANT_OP[node.binop](node) + node.value = CONSTANT_BINOP[node.binop](node) node.is_constant = node[1].is_constant and (not node[2] or node[2].is_constant) end end) @@ -406,6 +437,13 @@ local function fmt_lvalue (node, with_scope) return ('key %s in %s'):format(fmt_val(node[2].value), base), function_local end + -- + if node.exp == 'OP' and node.binop == 'HASHTAG' and #node == 1 then + local base, is_local = fmt_lvalue(node[1], with_scope) + return ('length of %s'):format(base), is_local + end + + --print(require'pretty'(node)) error 'Not implemented yet!' end @@ -413,7 +451,8 @@ local function fmt_prefix (ast, call_info) assert(type(ast) == 'table') -- local name, is_function_local = fmt_lvalue(ast, true) - local func_name = is_function_local and (' to '..get_function_name(call_info)) or '' + local binder = ast.node == 'argument' and 'to' or 'in' + local func_name = is_function_local and (' '..binder..' '..get_function_name(call_info)) or '' return ('bad %s%s'):format(name, func_name) end @@ -680,6 +719,7 @@ local function determine_error_message (call_info, msg, condition) elseif not ast.exp then error(('[assert-gooder/internal]: Root node did not have expression type.')) else + --print(require'pretty'(ast)) error(('[assert-gooder/internal]: Unknown expression type %s'):format(ast.exp)) end end diff --git a/lua_lang.lua b/lua_lang.lua index 40c077b..03ea771 100644 --- a/lua_lang.lua +++ b/lua_lang.lua @@ -53,7 +53,7 @@ return Lexer { -- { '%d+%.?%d*', 'NUMBER' }, { '%d*%.?%d+', 'NUMBER' }, - { '[%a_][%d%a_]*', 'IDENTIFIER' }, + { '[_a-zA-Z\128-\255][_a-zA-Z0-9\128-\255]*', 'IDENTIFIER' }, { '\".-\"', 'STRING' }, { '\'.-\'', 'STRING' }, { '%[%[.-%]%]', 'STRING' },