diff --git a/src/asl/parser.go b/src/asl/parser.go index 2766ae0..8315e1b 100644 --- a/src/asl/parser.go +++ b/src/asl/parser.go @@ -6,350 +6,350 @@ import ( // Parses tokens, validates code to a specific degree // and writes SQF code into desired location. -func Parse(token []Token, prettyPrinting bool) string { - if !initParser(token, prettyPrinting) { +func (c *Compiler) Parse(token []Token, prettyPrinting bool) string { + if !c.initParser(token, prettyPrinting) { return "" } - for tokenIndex < len(token) { - parseBlock() + for c.tokenIndex < len(token) { + c.parseBlock() } - return out + return c.out } -func parseBlock() { - if accept("var") { - parseVar() - } else if accept("if") { - parseIf() - } else if accept("while") { - parseWhile() - } else if accept("switch") { - parseSwitch() - } else if accept("for") { - parseFor() - } else if accept("foreach") { - parseForeach() - } else if accept("func") { - parseFunction() - } else if accept("return") { - parseReturn() - } else if accept("try") { - parseTryCatch() - } else if accept("exitwith") { - parseExitWith() - } else if accept("waituntil") { - parseWaitUntil() - } else if accept("case") || accept("default") { +func (c *Compiler) parseBlock() { + if c.accept("var") { + c.parseVar() + } else if c.accept("if") { + c.parseIf() + } else if c.accept("while") { + c.parseWhile() + } else if c.accept("switch") { + c.parseSwitch() + } else if c.accept("for") { + c.parseFor() + } else if c.accept("foreach") { + c.parseForeach() + } else if c.accept("func") { + c.parseFunction() + } else if c.accept("return") { + c.parseReturn() + } else if c.accept("try") { + c.parseTryCatch() + } else if c.accept("exitwith") { + c.parseExitWith() + } else if c.accept("waituntil") { + c.parseWaitUntil() + } else if c.accept("case") || c.accept("default") { return } else { - parseStatement() + c.parseStatement() } - if !end() && !accept("}") { - parseBlock() + if !c.end() && !c.accept("}") { + c.parseBlock() } } -func parseVar() { - expect("var") - appendOut(get().token, false) - next() +func (c *Compiler) parseVar() { + c.expect("var") + c.appendOut(c.get().token, false) + c.next() - if accept("=") { - next() - appendOut(" = ", false) + if c.accept("=") { + c.next() + c.appendOut(" = ", false) - if accept("[") { - parseArray() + if c.accept("[") { + c.parseArray() } else { - parseExpression(true) + c.parseExpression(true) } } - expect(";") - appendOut(";", true) + c.expect(";") + c.appendOut(";", true) } -func parseArray() { - expect("[") - appendOut("[", false) +func (c *Compiler) parseArray() { + c.expect("[") + c.appendOut("[", false) - if !accept("]") { - parseExpression(true) + if !c.accept("]") { + c.parseExpression(true) - for accept(",") { - next() - appendOut(",", false) - parseExpression(true) + for c.accept(",") { + c.next() + c.appendOut(",", false) + c.parseExpression(true) } } - expect("]") - appendOut("]", false) + c.expect("]") + c.appendOut("]", false) } -func parseIf() { - expect("if") - appendOut("if (", false) - parseExpression(true) - appendOut(") then {", true) - expect("{") - parseBlock() - expect("}") +func (c *Compiler) parseIf() { + c.expect("if") + c.appendOut("if (", false) + c.parseExpression(true) + c.appendOut(") then {", true) + c.expect("{") + c.parseBlock() + c.expect("}") - if accept("else") { - next() - expect("{") - appendOut("} else {", true) - parseBlock() - expect("}") + if c.accept("else") { + c.next() + c.expect("{") + c.appendOut("} else {", true) + c.parseBlock() + c.expect("}") } - appendOut("};", true) + c.appendOut("};", true) } -func parseWhile() { - expect("while") - appendOut("while {", false) - parseExpression(true) - appendOut("} do {", true) - expect("{") - parseBlock() - expect("}") - appendOut("};", false) +func (c *Compiler) parseWhile() { + c.expect("while") + c.appendOut("while {", false) + c.parseExpression(true) + c.appendOut("} do {", true) + c.expect("{") + c.parseBlock() + c.expect("}") + c.appendOut("};", false) } -func parseSwitch() { - expect("switch") - appendOut("switch (", false) - parseExpression(true) - appendOut(") do {", true) - expect("{") - parseSwitchBlock() - expect("}") - appendOut("};", true) +func (c *Compiler) parseSwitch() { + c.expect("switch") + c.appendOut("switch (", false) + c.parseExpression(true) + c.appendOut(") do {", true) + c.expect("{") + c.parseSwitchBlock() + c.expect("}") + c.appendOut("};", true) } -func parseSwitchBlock() { - if accept("}") { +func (c *Compiler) parseSwitchBlock() { + if c.accept("}") { return } - if accept("case") { - next() - appendOut("case ", false) - parseExpression(true) - expect(":") - appendOut(":", true) + if c.accept("case") { + c.next() + c.appendOut("case ", false) + c.parseExpression(true) + c.expect(":") + c.appendOut(":", true) - if !accept("case") && !accept("}") && !accept("default") { - appendOut("{", true) - parseBlock() - appendOut("};", true) + if !c.accept("case") && !c.accept("}") && !c.accept("default") { + c.appendOut("{", true) + c.parseBlock() + c.appendOut("};", true) } - } else if accept("default") { - next() - expect(":") - appendOut("default:", true) + } else if c.accept("default") { + c.next() + c.expect(":") + c.appendOut("default:", true) - if !accept("}") { - appendOut("{", true) - parseBlock() - appendOut("};", true) + if !c.accept("}") { + c.appendOut("{", true) + c.parseBlock() + c.appendOut("};", true) } } - parseSwitchBlock() + c.parseSwitchBlock() } -func parseFor() { - expect("for") - appendOut("for [{", false) +func (c *Compiler) parseFor() { + c.expect("for") + c.appendOut("for [{", false) // var in first assignment is optional - if accept("var") { - next() + if c.accept("var") { + c.next() } - parseExpression(true) - expect(";") - appendOut("}, {", false) - parseExpression(true) - expect(";") - appendOut("}, {", false) - parseExpression(true) - appendOut("}] do {", true) - expect("{") - parseBlock() - expect("}") - appendOut("};", true) + c.parseExpression(true) + c.expect(";") + c.appendOut("}, {", false) + c.parseExpression(true) + c.expect(";") + c.appendOut("}, {", false) + c.parseExpression(true) + c.appendOut("}] do {", true) + c.expect("{") + c.parseBlock() + c.expect("}") + c.appendOut("};", true) } -func parseForeach() { - expect("foreach") - expr := parseExpression(false) - expect("{") - appendOut("{", true) - parseBlock() - expect("}") - appendOut("} forEach ("+expr+");", true) +func (c *Compiler) parseForeach() { + c.expect("foreach") + expr := c.parseExpression(false) + c.expect("{") + c.appendOut("{", true) + c.parseBlock() + c.expect("}") + c.appendOut("} forEach ("+expr+");", true) } -func parseFunction() { - expect("func") - appendOut(get().token+" = {", true) - next() - expect("(") - parseFunctionParameter() - expect(")") - expect("{") - parseBlock() - expect("}") - appendOut("};", true) +func (c *Compiler) parseFunction() { + c.expect("func") + c.appendOut(c.get().token+" = {", true) + c.next() + c.expect("(") + c.parseFunctionParameter() + c.expect(")") + c.expect("{") + c.parseBlock() + c.expect("}") + c.appendOut("};", true) } -func parseFunctionParameter() { +func (c *Compiler) parseFunctionParameter() { // empty parameter list - if accept("{") { + if c.accept("{") { return } - appendOut("params [", false) + c.appendOut("params [", false) - for !accept(")") { - name := get().token - next() + for !c.accept(")") { + name := c.get().token + c.next() - if accept("=") { - next() - value := get().token - next() - appendOut("[\""+name+"\","+value+"]", false) + if c.accept("=") { + c.next() + value := c.get().token + c.next() + c.appendOut("[\""+name+"\","+value+"]", false) } else { - appendOut("\""+name+"\"", false) + c.appendOut("\""+name+"\"", false) } - if !accept(")") { - expect(",") - appendOut(",", false) + if !c.accept(")") { + c.expect(",") + c.appendOut(",", false) } } - appendOut("];", true) + c.appendOut("];", true) } -func parseReturn() { - expect("return") - appendOut("return ", false) - parseExpression(true) - expect(";") - appendOut(";", true) +func (c *Compiler) parseReturn() { + c.expect("return") + c.appendOut("return ", false) + c.parseExpression(true) + c.expect(";") + c.appendOut(";", true) } -func parseTryCatch() { - expect("try") - expect("{") - appendOut("try {", true) - parseBlock() - expect("}") - expect("catch") - expect("{") - appendOut("} catch {", true) - parseBlock() - expect("}") - appendOut("};", true) +func (c *Compiler) parseTryCatch() { + c.expect("try") + c.expect("{") + c.appendOut("try {", true) + c.parseBlock() + c.expect("}") + c.expect("catch") + c.expect("{") + c.appendOut("} catch {", true) + c.parseBlock() + c.expect("}") + c.appendOut("};", true) } -func parseExitWith() { - expect("exitwith") - expect("{") - appendOut("if (true) exitWith {", true) - parseBlock() - expect("}") - appendOut("};", true) +func (c *Compiler) parseExitWith() { + c.expect("exitwith") + c.expect("{") + c.appendOut("if (true) exitWith {", true) + c.parseBlock() + c.expect("}") + c.appendOut("};", true) } -func parseWaitUntil() { - expect("waituntil") - expect("(") - appendOut("waitUntil {", false) - parseExpression(true) +func (c *Compiler) parseWaitUntil() { + c.expect("waituntil") + c.expect("(") + c.appendOut("waitUntil {", false) + c.parseExpression(true) - if accept(";") { - next() - appendOut(";", false) - parseExpression(true) + if c.accept(";") { + c.next() + c.appendOut(";", false) + c.parseExpression(true) } - expect(")") - expect(";") - appendOut("};", true) + c.expect(")") + c.expect(";") + c.appendOut("};", true) } -func parseInlineCode() string { - expect("code") - expect("(") +func (c *Compiler) parseInlineCode() string { + c.expect("code") + c.expect("(") - code := get().token - next() + code := c.get().token + c.next() output := "{}" if len(code) > 2 { - output = "{"+Parse(Tokenize([]byte(code[1:len(code)-1])), pretty)+"}" + //output = "{"+Parse(Tokenize([]byte(code[1:len(code)-1])), pretty)+"}" } - expect(")") + c.expect(")") return output } // Everything that does not start with a keyword. -func parseStatement() { +func (c *Compiler) parseStatement() { // empty block - if accept("}") || accept("case") || accept("default") { + if c.accept("}") || c.accept("case") || c.accept("default") { return } // variable or function name - name := get().token - next() + name := c.get().token + c.next() - if accept("=") { - appendOut(name, false) - parseAssignment() + if c.accept("=") { + c.appendOut(name, false) + c.parseAssignment() } else { - parseFunctionCall(true, name) - expect(";") - appendOut(";", true) + c.parseFunctionCall(true, name) + c.expect(";") + c.appendOut(";", true) } - if !end() { - parseBlock() + if !c.end() { + c.parseBlock() } } -func parseAssignment() { - expect("=") - appendOut(" = ", false) - parseExpression(true) - expect(";") - appendOut(";", true) +func (c *Compiler) parseAssignment() { + c.expect("=") + c.appendOut(" = ", false) + c.parseExpression(true) + c.expect(";") + c.appendOut(";", true) } -func parseFunctionCall(out bool, name string) string { +func (c *Compiler) parseFunctionCall(out bool, name string) string { output := "" - expect("(") - leftParams, leftParamCount := parseParameter(false) - expect(")") + c.expect("(") + leftParams, leftParamCount := c.parseParameter(false) + c.expect(")") - if accept("(") { + if c.accept("(") { // buildin function - next() - rightParams, rightParamCount := parseParameter(false) - expect(")") + c.next() + rightParams, rightParamCount := c.parseParameter(false) + c.expect(")") if leftParamCount > 1 { leftParams = "[" + leftParams + "]" @@ -369,143 +369,143 @@ func parseFunctionCall(out bool, name string) string { } if out { - appendOut(output, false) + c.appendOut(output, false) } return output } -func parseParameter(out bool) (string, int) { +func (c *Compiler) parseParameter(out bool) (string, int) { output := "" count := 0 - for !accept(")") { - output += parseExpression(out) + for !c.accept(")") { + output += c.parseExpression(out) count++ - if !accept(")") { - expect(",") + if !c.accept(")") { + c.expect(",") output += ", " } } if out { - appendOut(output, false) + c.appendOut(output, false) } return output, count } -func parseExpression(out bool) string { - output := parseArith() +func (c *Compiler) parseExpression(out bool) string { + output := c.parseArith() - for accept("<") || accept(">") || accept("&") || accept("|") || accept("=") || accept("!") { - if accept("<") { + for c.accept("<") || c.accept(">") || c.accept("&") || c.accept("|") || c.accept("=") || c.accept("!") { + if c.accept("<") { output += "<" - next() - } else if accept(">") { + c.next() + } else if c.accept(">") { output += ">" - next() - } else if accept("&") { - next() - expect("&") + c.next() + } else if c.accept("&") { + c.next() + c.expect("&") output += "&&" - } else if accept("|") { - next() - expect("|") + } else if c.accept("|") { + c.next() + c.expect("|") output += "||" - } else if accept("=") { + } else if c.accept("=") { output += "=" - next() + c.next() } else { - next() - expect("=") + c.next() + c.expect("=") output += "!=" } - if accept("=") { + if c.accept("=") { output += "=" - next() + c.next() } - output += parseExpression(false) + output += c.parseExpression(false) } if out { - appendOut(output, false) + c.appendOut(output, false) } return output } -func parseIdentifier() string { +func (c *Compiler) parseIdentifier() string { output := "" - if accept("code") { - output += parseInlineCode() - } else if seek("(") && !accept("!") && !accept("-") { - name := get().token - next() - output = "(" + parseFunctionCall(false, name) + ")" - } else if seek("[") { - output += "("+get().token - next() - expect("[") - output += " select ("+parseExpression(false)+"))" - expect("]") - } else if accept("!") || accept("-") { - output = get().token - next() - output += parseTerm() + if c.accept("code") { + output += c.parseInlineCode() + } else if c.seek("(") && !c.accept("!") && !c.accept("-") { + name := c.get().token + c.next() + output = "(" + c.parseFunctionCall(false, name) + ")" + } else if c.seek("[") { + output += "("+c.get().token + c.next() + c.expect("[") + output += " select ("+c.parseExpression(false)+"))" + c.expect("]") + } else if c.accept("!") || c.accept("-") { + output = c.get().token + c.next() + output += c.parseTerm() } else { - output = get().token - next() + output = c.get().token + c.next() } return output } -func parseTerm() string { - if accept("(") { - expect("(") - output := "(" + parseExpression(false) + ")" - expect(")") +func (c *Compiler) parseTerm() string { + if c.accept("(") { + c.expect("(") + output := "(" + c.parseExpression(false) + ")" + c.expect(")") return output } - return parseIdentifier() + return c.parseIdentifier() } -func parseFactor() string { - output := parseTerm() +func (c *Compiler) parseFactor() string { + output := c.parseTerm() - for accept("*") || accept("/") { // TODO: modulo? - if accept("*") { + for c.accept("*") || c.accept("/") { // TODO: modulo? + if c.accept("*") { output += "*" } else { output += "/" } - next() - output += parseExpression(false) + c.next() + output += c.parseExpression(false) } return output } -func parseArith() string { - output := parseFactor() +func (c *Compiler) parseArith() string { + output := c.parseFactor() - for accept("+") || accept("-") { - if accept("+") { + for c.accept("+") || c.accept("-") { + if c.accept("+") { output += "+" } else { output += "-" } - next() - output += parseExpression(false) + c.next() + output += c.parseExpression(false) } return output diff --git a/src/asl/parserHelper.go b/src/asl/parserHelper.go index 403f957..bbdbf79 100644 --- a/src/asl/parserHelper.go +++ b/src/asl/parserHelper.go @@ -1,81 +1,83 @@ package asl -var tokens []Token -var tokenIndex int -var out string -var offset int -var pretty bool +type Compiler struct { + tokens []Token + tokenIndex int + out string + offset int + pretty bool +} // Initilizes the parser. -func initParser(token []Token, prettyPrinting bool) bool { +func (c *Compiler) initParser(token []Token, prettyPrinting bool) bool { if len(token) == 0 { return false } - tokens = token - tokenIndex = 0 - out = "" - offset = 0 - pretty = prettyPrinting + c.tokens = token + c.tokenIndex = 0 + c.out = "" + c.offset = 0 + c.pretty = prettyPrinting return true } // Returns true, if current token matches expected one. // Does not throw parse errors and checks if token is available. -func accept(token string) bool { - return tokenIndex < len(tokens) && tokenEqual(token, get()) +func (c *Compiler) accept(token string) bool { + return c.tokenIndex < len(c.tokens) && c.tokenEqual(token, c.get()) } // Hard version of "accept". // Throws if current token does not match expected one. -func expect(token string) { - if !tokenEqual(token, get()) { - panic("Parse error, expected '" + token + "' but was '" + get().token + "'") +func (c *Compiler) expect(token string) { + if !c.tokenEqual(token, c.get()) { + panic("Parse error, expected '" + token + "' but was '" + c.get().token + "'") } - next() + c.next() } // Returns true, if the next token matches expected one. // Does not throw parse errors and checks if token is available. -func seek(token string) bool { - if tokenIndex+1 >= len(tokens) { +func (c *Compiler) seek(token string) bool { + if c.tokenIndex+1 >= len(c.tokens) { return false } - return tokenEqual(token, tokens[tokenIndex+1]) + return c.tokenEqual(token, c.tokens[c.tokenIndex+1]) } // Increases token counter, so that the next token is compared. -func next() { - tokenIndex++ +func (c *Compiler) next() { + c.tokenIndex++ } // Returns current token or throws, if no more tokens are available. -func get() Token { - if tokenIndex >= len(tokens) { +func (c *Compiler) get() Token { + if c.tokenIndex >= len(c.tokens) { panic("No more tokens") } - return tokens[tokenIndex] + return c.tokens[c.tokenIndex] } // Returns true if the end of input code was reached. -func end() bool { - return tokenIndex == len(tokens) +func (c *Compiler) end() bool { + return c.tokenIndex == len(c.tokens) } // Checks if two strings match. -func tokenEqual(a string, b Token) bool { +func (c *Compiler) tokenEqual(a string, b Token) bool { return a == b.token } // Appends the output string to current SQF code output. -func appendOut(str string, newLine bool) { - out += str +func (c *Compiler) appendOut(str string, newLine bool) { + c.out += str - if newLine && pretty { - out += "\r\n" + if newLine && c.pretty { + c.out += "\r\n" } } diff --git a/src/asl/parser_test.go b/src/asl/parser_test.go index 5657977..a02137e 100644 --- a/src/asl/parser_test.go +++ b/src/asl/parser_test.go @@ -155,8 +155,9 @@ func getCompiled(t *testing.T, file string) string { } tokens := asl.Tokenize(code) + compiler := asl.Compiler{} - return asl.Parse(tokens, true) + return compiler.Parse(tokens, true) } func equal(t *testing.T, got, want string) { diff --git a/src/main/asl.go b/src/main/asl.go index 2c500ba..2359830 100644 --- a/src/main/asl.go +++ b/src/main/asl.go @@ -101,7 +101,8 @@ func compile(path string) { } token := asl.Tokenize(code) - sqf := asl.Parse(token, pretty) + compiler := asl.Compiler{} + sqf := compiler.Parse(token, pretty) os.MkdirAll(filepath.FromSlash(path+PathSeparator+aslFiles[i].out), 0777) err = ioutil.WriteFile(out, []byte(sqf), 0666)