1
0

Compare commits

...

2 Commits

Author SHA1 Message Date
aec8db9c15 The lost additions 2023-12-12 23:28:25 +01:00
9bfcd3beb3 Added a bunch of constant evaluations 2018-03-23 12:26:45 +01:00
5 changed files with 74 additions and 11 deletions

0
.gitignore vendored Normal file → Executable file
View File

View File

@ -1,6 +1,4 @@
require 'errors' 'shunt' . enable_strict_globals ()
---- Algorithm
local DEFAULT_ASSOC = 'left'

View File

@ -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,6 +274,28 @@ local function for_each_node_in_ast (ast, func)
return func(ast)
end
local CONSTANT_BINOP = {}
local CONSTANT_UNOP = {}
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')
assert(type(info) == 'table')
@ -260,16 +305,26 @@ local function populate_ast_with_semantics (ast, info)
node.exp, node.token = node.token, nil
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)
elseif node.exp == 'OP' and node.binop == 'DOT' then
assert(node[1].value and node[2].value)
node.value = node[1].value[ node[2].value ] --TODO
node.is_constant = true
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_BINOP[node.binop](node)
node.is_constant = node[1].is_constant and (not node[2] or node[2].is_constant)
end
end)
end
--------------------------------------------------------------------------------
@ -382,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
@ -389,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
@ -656,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

View File

@ -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' },

View File

@ -5,3 +5,4 @@ local TEST_SUITE = require "TestSuite" 'assert-gooder'
TEST_SUITE:addModules 'test/test_*.lua'
TEST_SUITE:enableStrictGlobal()
TEST_SUITE:runTests()