From de420a8111d115c9e02c15ee589cd913eb463f81 Mon Sep 17 00:00:00 2001 From: Ed94 Date: Wed, 20 Jul 2022 14:57:26 -0400 Subject: [PATCH] Lecture 6 complete. --- App/EoI/Lectures/Lecture.5.Notes.md | 0 App/EoI/Lectures/Lecture.6.Notes.md | 13 ++ App/EoI/Scripts/EoI_Viewer.gd | 4 +- App/EoI/Scripts/Eva.gd | 234 +++++++++++++++++++++++----- App/RDP/Scripts/Lexer.gd | 6 +- App/RDP/Scripts/Parser.gd | 1 - App/RegM/Scripts/SRegex.gd | 56 ++++--- Bootstrap_LangStudies.Windows.bat | 2 + 8 files changed, 243 insertions(+), 73 deletions(-) delete mode 100644 App/EoI/Lectures/Lecture.5.Notes.md diff --git a/App/EoI/Lectures/Lecture.5.Notes.md b/App/EoI/Lectures/Lecture.5.Notes.md deleted file mode 100644 index e69de29..0000000 diff --git a/App/EoI/Lectures/Lecture.6.Notes.md b/App/EoI/Lectures/Lecture.6.Notes.md index e69de29..c72f5bf 100644 --- a/App/EoI/Lectures/Lecture.6.Notes.md +++ b/App/EoI/Lectures/Lecture.6.Notes.md @@ -0,0 +1,13 @@ +# Environment +A repository of variables and functions defined in a scope. + +## Structure + +Record: Actual storage, table, etc. +Parent: Optional refrence to a parent environment. + +## Interface + +Define: Variable +Assign: Value to a varaible +Lookup: Variable \ No newline at end of file diff --git a/App/EoI/Scripts/EoI_Viewer.gd b/App/EoI/Scripts/EoI_Viewer.gd index a6a3926..b1dcd65 100644 --- a/App/EoI/Scripts/EoI_Viewer.gd +++ b/App/EoI/Scripts/EoI_Viewer.gd @@ -18,16 +18,18 @@ var eva = preload("Eva.gd").new() # UX -------------------------------------------------------- onready var Editor = get_node("Editor_TEdit") onready var Output = get_node("Output_TEdit") +onready var Debug = get_node("Debug_TEdit") onready var Eva_Btn = get_node("VBox/Eva_Interpret_Btn") onready var Back_Btn = get_node("VBox/Back_Btn") func evaBtn_pressed(): - eva.init(Editor.text) + eva.init(Editor.text, Output) var ast = eva.parse() Output.text = eva.eval(ast) + Debug.text = JSON.print(eva.Records, "\t") func backBtn_pressed(): queue_free() diff --git a/App/EoI/Scripts/Eva.gd b/App/EoI/Scripts/Eva.gd index 2849614..e3ad685 100644 --- a/App/EoI/Scripts/Eva.gd +++ b/App/EoI/Scripts/Eva.gd @@ -2,20 +2,24 @@ extends Object var SRegEx = preload("res://RegM/Scripts/SRegex.gd").new() - +# ---------------------------------------------------------- Lexer const TType : Dictionary = \ { - fmt_S = "Formatting", + fmt_S = "Formatting", cmt_SL = "Comment Single-Line", cmt_ML = "Comment Multi-Line", def_Start = "Expression Start", def_End = "Expression End", + def_Var = "Variable", - literal_Number = "LIteral: Number", + literal_Number = "Literal: Number", literal_String = "Literal: String", - operator = "Operator" + op_Assgin = "Assignment", + op_Numeric = "op_Numeric", + + identifier = "Identifier" } const Spec : Dictionary = \ @@ -26,26 +30,37 @@ const Spec : Dictionary = \ TType.fmt_S : "start whitespace.repeat(1-).lazy", TType.def_Start : "start \\(", - TType.def_End : "start \\)", + TType.def_End : "start \\)", + TType.def_Var : "start \"var\"", TType.literal_Number : \ """start - set(+ \\-).repeat(0-1) + set(+ \\-).repeat(0-1) ( set(0-9).repeat(1-) \\. ).repeat(0-1) set(0-9).repeat(1-) """, TType.literal_String : "start \\\" !set( \\\" ).repeat(0-) \\\" ", - TType.operator : "start set(+ \\-)", + TType.op_Assgin : "start \"set\"", + TType.op_Numeric : "start set(+ \\- * /)", + + TType.identifier : + """start + ( + set(A-z).repeat(1-) + set(\\- _).repeat(0-1) + ) + .repeat(0-1) + """ } class Token: var Type : String var Value : String - - func is_Literal(): - return Type == TType.literal_Number || Type == TType.literal_String; + func is_Literal(): + return Type == TType.literal_Number || Type == TType.literal_String; + var SourceText : String var Cursor : int @@ -56,13 +71,16 @@ var TokenIndex : int = 0 func compile_regex(): for type in TType.values() : - var \ - regex = RegEx.new() - regex.compile( SRegEx.transpile(Spec[type]) ) + var regex = RegEx.new() + var result = SRegEx.compile(Spec[type]) + + regex.compile( result ) SpecRegex[type] = regex -func init(programSrcText): +func init(programSrcText, errorOutput): + ErrorOutput = errorOutput + SourceText = programSrcText Cursor = 0 TokenIndex = 0 @@ -73,7 +91,6 @@ func init(programSrcText): tokenize() func next_Token(): - var nextToken = null if Tokens.size() > TokenIndex : @@ -122,11 +139,11 @@ func tokenize(): break; if error : - var assertStrTmplt = "next_token: Source text not understood by tokenizer at Cursor pos: {value} -: {txt}" + var assertStrTmplt = "Lexer - tokenize: Source text not understood by tokenizer at Cursor pos: {value} -: {txt}" var assertStr = assertStrTmplt.format({"value" : Cursor, "txt" : srcLeft}) - assert(true != true, assertStr) + throw(assertStr) return -# ---------------------------------------------------------- Lexer +# ---------------------------------------------------------- Lexer END # ---------------------------------------------------------- Parser @@ -137,8 +154,15 @@ const NType = \ literal_Number = "Literal: Number", literal_String = "Literal: String", + op_Assign = "Assignment", + op_Add = "+", - op_Mult = "*" + op_Sub = "-", + op_Mult = "*", + op_Div = "/", + + identifier = "Identifier", + variable = "Variable" } class ASTNode: @@ -170,7 +194,6 @@ class ASTNode: func string(): return arg(1).substr(1, arg(1).length() -2) - # Serialization ---------------------------------------------------- func array_Serialize(array, fn_objSerializer) : @@ -216,12 +239,12 @@ var NextToken : Token func eat(tokenType): var currToken = NextToken - assert(currToken != null, "eat: NextToken was null") + check(currToken != null, "Parser - eat: NextToken was null") - var assertStrTmplt = "eat: Unexpected token: {value}, expected: {type}" + var assertStrTmplt = "Parser - eat: Unexpected token: {value}, expected: {type}" var assertStr = assertStrTmplt.format({"value" : currToken.Value, "type" : tokenType}) - assert(currToken.Type == tokenType, assertStr) + check(currToken.Type == tokenType, assertStr) NextToken = next_Token() @@ -232,6 +255,9 @@ func parse(): if NextToken.Type == TType.def_Start: return parse_Expression() + + if NextToken.Type == TType.identifier: + return parse_Identifier() if NextToken.is_Literal(): return parse_Literal() @@ -240,37 +266,102 @@ func parse_Expression(): eat(TType.def_Start) var node : ASTNode - if NextToken.Type == TType.operator: - node = parse_Operator() + if NextToken.Type == TType.def_Var: + node = parse_Variable() + + if NextToken.Type == TType.op_Assgin: + node = parse_op_Assign() + + elif NextToken.Type == TType.op_Numeric: + node = parse_op_Numeric() var arg = 1 while NextToken.Type != TType.def_End: - node.add_Expr( parse_Literal() ) + if NextToken.Type == TType.def_Start: + node.add_Expr( parse_Expression() ) + else : + node.add_Expr( parse_Literal() ) - if NextToken.is_Literal(): + elif NextToken.is_Literal(): node = parse_Literal() eat(TType.def_End) return node - -func parse_Operator(): + +func parse_Variable(): var \ node = ASTNode.new() + node.set_Type(NType.variable) + eat(TType.def_Var) + + check( NextToken.Type == TType.identifier, + String("Parser - parse_Variable: NextToken should have been identifier. TokenData - Type: {type} Value: {value}") \ + .format({"type" : NextToken.Type, "value" : NextToken.Value }) + ) + + node.add_TokenValue( NextToken ) + eat(TType.identifier) + + if NextToken.Type == TType.def_Start : + node.add_Expr( parse_Expression() ) + + else : + node.add_Expr( parse_Literal() ) + + return node + +func parse_Identifier(): + var \ + node = ASTNode.new() + node.set_Type(NType.identifier) + node.add_TokenValue(NextToken) + + eat(TType.identifier) + + return node + +func parse_op_Assign(): + var \ + node = ASTNode.new() + node.set_type(NType.op_Assign) + + eat(TType.op_Assgin) + + check( NextToken.Type != TType.identifier, + String("Parser - parse_op_Assign: NextToken should have been identifier, Type: {type} Value: {value}") \ + .format({"type" : NextToken.Type, "value" : NextToken.Value }) + ) + + node.add_TokenValue( NextToken.Value ) + + if NextToken.is_Literal() : + node.add_Expr( parse_Literal() ) + + elif NextToken.Type == TType.def_Start : + node.add_Expr( parse_Expression() ) + + return node + +func parse_op_Numeric(): + var node = ASTNode.new() match NextToken.Value: NType.op_Add: node.set_Type(NType.op_Add) + NType.op_Sub: + node.set_Type(NType.op_Sub) NType.op_Mult: node.set_Type(NType.op_Mult) + NType.op_Div: + node.set_Type(NType.op_Div) - eat(TType.operator) + eat(TType.op_Numeric) return node func parse_Literal(): - var \ - node = ASTNode.new() + var node = ASTNode.new() match NextToken.Type: TType.literal_Number: @@ -289,28 +380,93 @@ func parse_Literal(): # ---------------------------------------------------------- Parser END +# ---------------------------------------------------------- Environment + +var Records : Dictionary + +func env_DefineVar(symbol : String, value) : + Records[symbol] = value + +func env_Lookup(symbol : String) : + check(Records.has(symbol), String("Symbol not found in environment records")) + + return Records[symbol] + +# ---------------------------------------------------------- Environment END + class_name Eva # ---------------------------------------------------------- GLOBALS - +var ErrorOutput # ---------------------------------------------------------- GLOBALS END # ---------------------------------------------------------- UTILITIES +func check( condition : bool, message : String): + assert(condition, message) + ErrorOutput.text = "Eva - Error: " + message func throw( message ): assert(false, message) + ErrorOutput.text = "Eva - Error: " + message # ---------------------------------------------------------- UTILITIES END func eval( ast ): - if ast.is_Number() : - return float(ast.arg(1)) + if ast.type() == NType.identifier : + return env_Lookup( ast.arg(1) ) + + if ast.type() == NType.variable : + var symbol = ast.arg(1) + var value = eval( ast.arg(2) ) + + env_DefineVar(symbol, value) + return value + if ast.is_String() : return ast.string() + + return String( eval_Numeric(ast) ) + + var msgT = "eval - Unimplemented: {ast}" + var msg = msgT.format({"ast" : JSON.print(ast.to_SExpression(), "\t") }) + throw(msg) + +func eval_Numeric( ast ): + if ast.is_Number() : + return float(ast.arg(1)) if ast.type() == NType.op_Add: - return String(eval( ast.arg(1) ) + eval( ast.arg(2) )) + var result = 0.0; var index = 1 + + while index <= ast.num_args(): + result += eval_Numeric( ast.arg(index) ) + index += 1 + + return result + + if ast.type() == NType.op_Sub: + var result = 0.0; var index = 1 + + while index <= ast.num_args(): + result -= eval_Numeric( ast.arg(index) ) + index += 1 + + return result if ast.type() == NType.op_Mult: - return String(eval( ast.arg(1) ) * eval( ast.arg(2) )) - - throw("Unimplemented") + var result = 1.0; var index = 1 + + while index <= ast.num_args(): + result *= eval_Numeric( ast.arg(index) ) + index += 1 + + return result + + if ast.type() == NType.op_Div: + var result = 1.0; var index = 1 + + while index <= ast.num_args(): + result /= eval_Numeric( ast.arg(index) ) + result += 1 + + return result + diff --git a/App/RDP/Scripts/Lexer.gd b/App/RDP/Scripts/Lexer.gd index 1588eb6..44b0cd7 100644 --- a/App/RDP/Scripts/Lexer.gd +++ b/App/RDP/Scripts/Lexer.gd @@ -127,9 +127,9 @@ const Spec : Dictionary = \ TokenType.op_LNot : "^!", # Arithmetic - TokenType.op_CAssign : "^[\\*\\/+-]=", + TokenType.op_CAssign : "^[\\*\\/+\\-]=", TokenType.op_Assign : "^=", - TokenType.op_Additive : "^[+-]", + TokenType.op_Additive : "^[+\\-]", TokenType.op_Multiplicative : "^[\\*\\/]", # Literals @@ -231,7 +231,7 @@ func compile_regex(): regex = RegEx.new() var original = Spec[type] - var transpiled = SRegEx.transpile(SSpec[type]) + var transpiled = SRegEx.compile(SSpec[type]) assert(transpiled == original, "transpiled did not match original") diff --git a/App/RDP/Scripts/Parser.gd b/App/RDP/Scripts/Parser.gd index d16de32..9b6e1b0 100644 --- a/App/RDP/Scripts/Parser.gd +++ b/App/RDP/Scripts/Parser.gd @@ -1035,7 +1035,6 @@ func parse_StringLiteral(): return node - # > Literal # BooleanLiteral # : true diff --git a/App/RegM/Scripts/SRegex.gd b/App/RegM/Scripts/SRegex.gd index e27c2e2..88397e1 100644 --- a/App/RegM/Scripts/SRegex.gd +++ b/App/RegM/Scripts/SRegex.gd @@ -664,7 +664,7 @@ func parse_GlyphDash(): var \ node = ASTNode.new() node.Type = NodeType.glyph - node.Value = "-" + node.Value = "\\-" return node @@ -894,22 +894,21 @@ func parse_String(): var ExprAST : ASTNode var RegexResult : String -func transpile(expression : String): +func compile(expression : String): init( expression ) NextToken = next_Token() ExprAST = parse_OpUnion(null) - return transiple_Union(ExprAST) + return compile_Union(ExprAST) -func transiple_Union(node : ASTNode): +func compile_Union(node : ASTNode): var result = "" var expressionLeft = node.Value if node.Type == NodeType.union : expressionLeft = node.Value[0].Value - - + for entry in expressionLeft : match entry.Type : NodeType.str_start: @@ -918,15 +917,15 @@ func transiple_Union(node : ASTNode): result += "$" NodeType.capture: - result += transpile_CaptureGroup(entry, false) + result += compile_CaptureGroup(entry, false) NodeType.look: - result += transpile_LookAhead(entry, false) + result += compile_LookAhead(entry, false) NodeType.ref: - result += transpile_Backreference(entry) + result += compile_Backreference(entry) NodeType.repeat: - result += transpile_Repeat(entry) + result += compile_Repeat(entry) NodeType.set: - result += transpile_Set(entry, false) + result += compile_Set(entry, false) NodeType.glyph: result += entry.Value @@ -942,19 +941,18 @@ func transiple_Union(node : ASTNode): result += entry.Value NodeType.string: - result += transpile_String(entry, false) + result += compile_String(entry, false) NodeType.op_not: - result += transpile_OpNot(entry) - + result += compile_OpNot(entry) if node.Type == NodeType.union && node.Value[1] != null : result += "|" - result += transiple_Union(node.Value[1]) + result += compile_Union(node.Value[1]) return result -func transpile_CaptureGroup(node : ASTNode, negate : bool): +func compile_CaptureGroup(node : ASTNode, negate : bool): var result = "" if negate : @@ -962,12 +960,12 @@ func transpile_CaptureGroup(node : ASTNode, negate : bool): else : result += "(" - result += transiple_Union(node.Value) + result += compile_Union(node.Value) result += ")" return result -func transpile_LookAhead(node : ASTNode, negate : bool): +func compile_LookAhead(node : ASTNode, negate : bool): var result = "" if negate : @@ -975,19 +973,19 @@ func transpile_LookAhead(node : ASTNode, negate : bool): else : result += "(?=" - result += transiple_Union(node.Value.Value) + result += compile_Union(node.Value.Value) result += ")" return result -func transpile_Backreference(node : ASTNode): +func compile_Backreference(node : ASTNode): var \ result = "\\" result += node.Value return result -func transpile_Repeat(node : ASTNode): +func compile_Repeat(node : ASTNode): var result = "" var vrange = node.Value[0] var lazy = node.Value[1] @@ -1013,7 +1011,7 @@ func transpile_Repeat(node : ASTNode): return result -func transpile_Set(node : ASTNode, negate : bool): +func compile_Set(node : ASTNode, negate : bool): var result = "" if negate : @@ -1023,7 +1021,7 @@ func transpile_Set(node : ASTNode, negate : bool): for entry in node.Value : if entry.Type == NodeType.op_not : - result += transpile_OpNot(entry) + result += compile_OpNot(entry) elif entry.Type == NodeType.between : result += entry.Value[0].Value result += "-" @@ -1035,7 +1033,7 @@ func transpile_Set(node : ASTNode, negate : bool): return result -func transpile_String(node : ASTNode, negate : bool): +func compile_String(node : ASTNode, negate : bool): var result = "" if negate : @@ -1052,14 +1050,14 @@ func transpile_String(node : ASTNode, negate : bool): return result -func transpile_OpNot(node : ASTNode): +func compile_OpNot(node : ASTNode): var result = "" var entry = node.Value match entry.Type : NodeType.capture: - result += transpile_CaptureGroup(entry, true) + result += compile_CaptureGroup(entry, true) NodeType.digit: result += "\\D" NodeType.word: @@ -1067,10 +1065,10 @@ func transpile_OpNot(node : ASTNode): NodeType.whitespace: result += "\\S" NodeType.look: - result += transpile_LookAhead(entry, true) + result += compile_LookAhead(entry, true) NodeType.string: - result += transpile_String(entry, true) + result += compile_String(entry, true) NodeType.set: - result += transpile_Set(entry, true) + result += compile_Set(entry, true) return result diff --git a/Bootstrap_LangStudies.Windows.bat b/Bootstrap_LangStudies.Windows.bat index d5ce113..4102849 100644 --- a/Bootstrap_LangStudies.Windows.bat +++ b/Bootstrap_LangStudies.Windows.bat @@ -41,4 +41,6 @@ if not exist Engine\gd\bin\godot.windows.opt.64.exe ( goto :opt_wait ) +timeout 2 + start /w build_project.bat