2022-07-20 06:27:19 -07:00
|
|
|
extends Object
|
|
|
|
|
2022-07-23 23:56:37 -07:00
|
|
|
# ---------------------------------------------------------- UTILITIES
|
|
|
|
var EvalOut
|
2022-07-20 06:27:19 -07:00
|
|
|
|
2022-07-23 23:56:37 -07:00
|
|
|
func check( condition : bool, message : String):
|
|
|
|
assert(condition, message)
|
|
|
|
if ! condition:
|
|
|
|
EvalOut.text = "Eva - Error: " + message
|
2022-07-20 06:27:19 -07:00
|
|
|
|
2022-07-23 23:56:37 -07:00
|
|
|
func throw( message ):
|
|
|
|
assert(false, message)
|
|
|
|
EvalOut.text = "Eva - Error: " + message
|
|
|
|
# ---------------------------------------------------------- UTILITIES END
|
2022-07-20 06:27:19 -07:00
|
|
|
|
2022-07-23 23:56:37 -07:00
|
|
|
class_name Eva
|
2022-07-20 06:27:19 -07:00
|
|
|
|
2022-07-23 23:56:37 -07:00
|
|
|
# ---------------------------------------------------------- GLOBALS
|
|
|
|
const Parser = preload("Parser.gd")
|
|
|
|
const NType = Parser.NType
|
2022-07-20 06:27:19 -07:00
|
|
|
|
2022-07-23 23:56:37 -07:00
|
|
|
const EvaEnv = preload("EvaEnv.gd")
|
|
|
|
var Env : EvaEnv
|
2022-07-20 06:27:19 -07:00
|
|
|
|
2022-07-23 23:56:37 -07:00
|
|
|
var Parent
|
|
|
|
# ---------------------------------------------------------- GLOBALS END
|
2022-07-20 06:27:19 -07:00
|
|
|
|
2022-07-24 04:54:17 -07:00
|
|
|
func get_class():
|
|
|
|
return "Eva"
|
|
|
|
|
2022-07-23 23:56:37 -07:00
|
|
|
func _init(parent, evalOut):
|
|
|
|
EvalOut = evalOut
|
|
|
|
Env = EvaEnv.new(EvalOut)
|
|
|
|
Parent = parent
|
2022-07-24 04:54:17 -07:00
|
|
|
|
|
|
|
if Parent == null:
|
|
|
|
Env.setup_Globals()
|
2022-07-20 06:27:19 -07:00
|
|
|
|
2022-07-23 23:56:37 -07:00
|
|
|
func eval( ast ):
|
2022-07-24 01:36:18 -07:00
|
|
|
match ast.type():
|
|
|
|
NType.program :
|
|
|
|
var index = 1;
|
|
|
|
while index < ast.num_args():
|
|
|
|
eval( ast.arg(index) )
|
|
|
|
index += 1
|
|
|
|
|
|
|
|
var result = eval( ast.arg(index) )
|
|
|
|
if result != null:
|
|
|
|
return String( result )
|
|
|
|
else:
|
|
|
|
return null
|
2022-07-20 06:27:19 -07:00
|
|
|
|
2022-07-24 01:36:18 -07:00
|
|
|
NType.block :
|
|
|
|
return eval_Block( ast )
|
|
|
|
|
2022-07-24 04:54:17 -07:00
|
|
|
NType.conditional :
|
2022-07-24 01:36:18 -07:00
|
|
|
var condition = eval( ast.arg(1) )
|
|
|
|
|
|
|
|
if condition:
|
|
|
|
# consequent
|
|
|
|
return eval( ast.arg(2) )
|
|
|
|
|
|
|
|
# Alternate
|
|
|
|
if ast.num_args() > 2:
|
|
|
|
return eval( ast.arg(3))
|
|
|
|
|
2022-07-24 04:54:17 -07:00
|
|
|
NType.expr_While :
|
2022-07-24 01:36:18 -07:00
|
|
|
var result
|
|
|
|
|
|
|
|
while eval( ast.arg(1) ):
|
|
|
|
result = eval( ast.arg(2) )
|
|
|
|
|
|
|
|
return result
|
2022-07-24 04:54:17 -07:00
|
|
|
|
|
|
|
NType.fn_User :
|
|
|
|
var symbol = ast.arg(1)
|
|
|
|
var fnDef = \
|
|
|
|
[
|
|
|
|
ast.arg(2), # Parameters
|
|
|
|
ast.arg(3), # Body
|
|
|
|
self # Closure (Environment capture)
|
|
|
|
]
|
|
|
|
|
|
|
|
Env.define(symbol, fnDef)
|
|
|
|
return Env.lookup(symbol)
|
2022-07-20 06:27:19 -07:00
|
|
|
|
2022-07-24 01:36:18 -07:00
|
|
|
NType.identifier :
|
2022-07-24 04:54:17 -07:00
|
|
|
return eval_Lookup( ast )
|
2022-07-20 06:27:19 -07:00
|
|
|
|
2022-07-24 01:36:18 -07:00
|
|
|
NType.op_Assign :
|
2022-07-24 04:54:17 -07:00
|
|
|
return eval_Assign( ast )
|
2022-07-24 01:36:18 -07:00
|
|
|
|
2022-07-24 04:54:17 -07:00
|
|
|
NType.op_Fn:
|
|
|
|
return eval_Func( ast )
|
2022-07-24 01:36:18 -07:00
|
|
|
|
|
|
|
NType.op_Greater:
|
|
|
|
return eval( ast.arg(1) ) > eval( ast.arg(2) )
|
|
|
|
NType.op_Lesser:
|
|
|
|
return eval( ast.arg(1) ) < eval( ast.arg(2) )
|
|
|
|
NType.op_GreaterEqual:
|
|
|
|
return eval( ast.arg(1) ) >= eval( ast.arg(2) )
|
|
|
|
NType.op_LesserEqual:
|
|
|
|
return eval( ast.arg(1) ) <= eval( ast.arg(2) )
|
|
|
|
|
|
|
|
NType.fn_Print :
|
|
|
|
return eval_Print( ast )
|
2022-07-20 06:27:19 -07:00
|
|
|
|
2022-07-24 01:36:18 -07:00
|
|
|
NType.variable :
|
|
|
|
var symbol = ast.arg(1)
|
2022-07-24 04:54:17 -07:00
|
|
|
var value
|
|
|
|
|
|
|
|
if ast.num_args() == 2:
|
|
|
|
value = eval( ast.arg(2) )
|
|
|
|
|
|
|
|
Env.define(symbol, value)
|
|
|
|
|
|
|
|
return Env.lookup(symbol)
|
2022-07-20 11:57:26 -07:00
|
|
|
|
2022-07-24 01:36:18 -07:00
|
|
|
if ast.is_Number() :
|
2022-07-23 23:56:37 -07:00
|
|
|
return float( ast.arg(1) )
|
2022-07-20 11:57:26 -07:00
|
|
|
|
2022-07-23 23:56:37 -07:00
|
|
|
elif ast.is_String() :
|
|
|
|
return ast.string()
|
2022-07-20 11:57:26 -07:00
|
|
|
|
2022-07-23 23:56:37 -07:00
|
|
|
return eval_Numeric( ast )
|
2022-07-20 06:27:19 -07:00
|
|
|
|
2022-07-23 23:56:37 -07:00
|
|
|
func eval_Block( ast ):
|
|
|
|
var eva_Block = get_script().new( self, EvalOut )
|
2022-07-20 11:57:26 -07:00
|
|
|
|
2022-07-23 23:56:37 -07:00
|
|
|
var result
|
2022-07-20 11:57:26 -07:00
|
|
|
|
2022-07-23 23:56:37 -07:00
|
|
|
var index = 1;
|
|
|
|
while index <= ast.num_args() :
|
|
|
|
result = eva_Block.eval( ast.arg(index) )
|
|
|
|
index += 1
|
2022-07-20 11:57:26 -07:00
|
|
|
|
2022-07-23 23:56:37 -07:00
|
|
|
return result
|
2022-07-20 11:57:26 -07:00
|
|
|
|
2022-07-24 04:54:17 -07:00
|
|
|
func eval_Lookup( ast ) :
|
|
|
|
var identifier = ast.arg(1)
|
|
|
|
|
|
|
|
if Parent != null && !Env.has( identifier):
|
|
|
|
return Parent.eval_Lookup( ast )
|
|
|
|
|
|
|
|
return Env.lookup( identifier )
|
|
|
|
|
|
|
|
func eval_Assign( ast, oriEva = null ) :
|
|
|
|
var symbol = ast.arg(1)
|
|
|
|
|
|
|
|
if Parent != null && !Env.has( symbol):
|
|
|
|
return Parent.eval_Assign( ast, self )
|
|
|
|
|
|
|
|
var value
|
|
|
|
|
|
|
|
if oriEva != null :
|
|
|
|
value = oriEva.eval( ast.arg(2) )
|
|
|
|
else :
|
|
|
|
value = eval( ast.arg(2) )
|
|
|
|
|
|
|
|
return Env.set( symbol, value )
|
|
|
|
|
|
|
|
func eval_Func( ast ):
|
|
|
|
var fn = eval_Lookup( ast )
|
|
|
|
var params = fn[0]
|
|
|
|
var body = fn[1]
|
|
|
|
var fnEva = get_script().new( fn[2], EvalOut )
|
|
|
|
|
|
|
|
if params.type() != NType.empty:
|
|
|
|
var index = 1
|
|
|
|
while index <= params.num_args():
|
|
|
|
var paramVal = eval( ast.arg(index + 1) )
|
|
|
|
fnEva.Env.define(params.arg(index), paramVal )
|
|
|
|
index += 1
|
|
|
|
|
|
|
|
return fnEva.eval( body )
|
|
|
|
|
2022-07-20 11:57:26 -07:00
|
|
|
func eval_Numeric( ast ):
|
2022-07-20 06:27:19 -07:00
|
|
|
if ast.type() == NType.op_Add:
|
2022-07-20 11:57:26 -07:00
|
|
|
var result = 0.0; var index = 1
|
|
|
|
|
|
|
|
while index <= ast.num_args():
|
2022-07-23 23:56:37 -07:00
|
|
|
result += eval( ast.arg(index) )
|
2022-07-20 11:57:26 -07:00
|
|
|
index += 1
|
|
|
|
|
|
|
|
return result
|
|
|
|
|
|
|
|
if ast.type() == NType.op_Sub:
|
2022-07-24 04:54:17 -07:00
|
|
|
if ast.num_args() == 2:
|
|
|
|
return -eval( ast.arg(1) )
|
|
|
|
|
2022-07-20 11:57:26 -07:00
|
|
|
var result = 0.0; var index = 1
|
|
|
|
|
|
|
|
while index <= ast.num_args():
|
2022-07-23 23:56:37 -07:00
|
|
|
result -= eval( ast.arg(index) )
|
2022-07-20 11:57:26 -07:00
|
|
|
index += 1
|
|
|
|
|
|
|
|
return result
|
2022-07-20 06:27:19 -07:00
|
|
|
|
|
|
|
if ast.type() == NType.op_Mult:
|
2022-07-20 11:57:26 -07:00
|
|
|
var result = 1.0; var index = 1
|
|
|
|
|
|
|
|
while index <= ast.num_args():
|
2022-07-23 23:56:37 -07:00
|
|
|
result *= eval( ast.arg(index) )
|
2022-07-20 11:57:26 -07:00
|
|
|
index += 1
|
|
|
|
|
|
|
|
return result
|
|
|
|
|
|
|
|
if ast.type() == NType.op_Div:
|
|
|
|
var result = 1.0; var index = 1
|
|
|
|
|
|
|
|
while index <= ast.num_args():
|
2022-07-23 23:56:37 -07:00
|
|
|
result /= eval( ast.arg(index) )
|
2022-07-20 11:57:26 -07:00
|
|
|
result += 1
|
|
|
|
|
|
|
|
return result
|
2022-07-24 01:36:18 -07:00
|
|
|
|
|
|
|
var msgT = "eval - Unimplemented: {ast}"
|
|
|
|
var msg = msgT.format({"ast" : JSON.print(ast.to_SExpression(), "\t") })
|
|
|
|
throw(msg)
|
2022-07-23 23:56:37 -07:00
|
|
|
|
|
|
|
func eval_Print( ast ):
|
|
|
|
EvalOut.text += "\n" + String( eval( ast.arg(1) ) )
|
|
|
|
return null
|
2022-07-20 11:57:26 -07:00
|
|
|
|
2022-07-23 23:56:37 -07:00
|
|
|
func get_EnvSnapshot():
|
2022-07-24 04:54:17 -07:00
|
|
|
var \
|
|
|
|
snapshot = EvaEnv.new(EvalOut)
|
|
|
|
snapshot.Records = Env.Records.duplicate(true)
|
2022-07-23 23:56:37 -07:00
|
|
|
|
|
|
|
if Parent != null:
|
2022-07-24 04:54:17 -07:00
|
|
|
snapshot[Parent] = Parent.get_EnvSnapshot()
|
2022-07-23 23:56:37 -07:00
|
|
|
|
2022-07-24 04:54:17 -07:00
|
|
|
return snapshot.to_Dictionary()
|