diff --git a/compiler/codegen.rb b/compiler/codegen.rb index 5a3a141..97bfe54 100644 --- a/compiler/codegen.rb +++ b/compiler/codegen.rb @@ -20,17 +20,24 @@ def generate(node) ] when IfNode - body_code = - if node.body.is_a?(Array) - node.body.map { |n| generate (n) }.join("\n") - else - generate(node.body) + compiled = "" + + first = node.condition + compiled << "if #{generate(first)} then\n" + compiled << node.body.map { |n| generate (n) }.join("\n") + + node.elif_blocks.each do |c| + compiled << "\nelseif #{generate(c.condition)} then\n" + compiled << c.body.map { |n| generate (n) }.join("\n") end - "if %s then \n %s \nend" % [ - generate(node.statement), - body_code - ] + if node.else_body + compiled << "\nelse\n" + compiled << node.else_body.map { |n| generate (n) }.join("\n") + end + + compiled << "\nend" + compiled when WhileNode body_code = @@ -44,6 +51,24 @@ def generate(node) generate(node.statement), body_code ] + + when SwitchNode + compiled = "" + node.cases.each_with_index do |c, i| + if i == 0 + compiled << "if #{generate(c.match)} == #{generate(node.value)} then\n" + else + compiled << "elseif #{generate(c.match)} == #{generate(node.value)} then\n" + end + + body_code = c.body.map { |b| generate(b) }.join("\n") + compiled << " #{body_code}\n" + + end + compiled << "end" + compiled + + when CallNode "%s(%s)" % [ node.name, diff --git a/compiler/parser.rb b/compiler/parser.rb index 76680e4..d56092b 100644 --- a/compiler/parser.rb +++ b/compiler/parser.rb @@ -1,5 +1,8 @@ DefNode = Struct.new(:name, :args, :body) -IfNode = Struct.new(:statement, :body) + +IfNode = Struct.new(:condition, :body, :elif_blocks, :else_body) +ElifBlock = Struct.new(:condition, :body) + WhileNode = Struct.new(:statement, :body) IntegerNode = Struct.new(:value) StringNode = Struct.new(:value) @@ -11,6 +14,8 @@ PrintNode = Struct.new(:args) ReturnNode = Struct.new(:statement) AndOrListNode = Struct.new(:items) +SwitchNode = Struct.new(:value, :cases) +CaseNode = Struct.new(:match, :body) LoveCallNode = Struct.new(:namespace, :name, :args) @@ -86,26 +91,71 @@ def parse_return end def parse_if + consume(:if) + condition = parse_expr + skip_newlines + if_body = [] + while !peek(:elif) && !peek(:else) && !peek(:end) + if_body << parse_statement + skip_newlines + end + + + elif_blocks = [] + while peek(:elif) + consume(:elif) + elif_condition = parse_expr + skip_newlines + + elif_body = [] + while !peek(:elif) && !peek(:else) && !peek(:end) + elif_body << parse_statement + skip_newlines + end + + elif_blocks << ElifBlock.new(elif_condition, elif_body) - if peek(:oparen) - consume(:oparen) - statement = parse_expr - consume(:cparen) - else - statement = parse_expr end - skip_newlines - body = [] - until peek(:end) - body << parse_statement + else_body = nil + if peek(:else) + consume(:else) skip_newlines + + else_body = [] + while !peek(:end) + else_body << parse_statement + skip_newlines + end end + consume(:end) - IfNode.new(statement, body) + + IfNode.new(condition, if_body, elif_blocks, else_body) + + end + # consume(:if) + + # if peek(:oparen) + # consume(:oparen) + # statement = parse_expr + # consume(:cparen) + # else + # statement = parse_expr + # end + # skip_newlines + # body = [] + + # until peek(:elif) peek(:end) + # body << parse_statement + # skip_newlines + # end + # consume(:end) + # IfNode.new(statement, body) + def parse_while consume(:while) @@ -129,6 +179,32 @@ def parse_while WhileNode.new(statement, body) end + def parse_switch + consume(:switch) + value = parse_expr + skip_newlines + + cases = [] + + while peek(:to) + consume(:to) + match = parse_expr + skip_newlines + + body = [] + + until peek(:to) || peek(:end) + body << parse_statement + skip_newlines + end + + cases << CaseNode.new(match, body) + end + + consume(:end) + SwitchNode.new(value, cases) + end + def parse_print consume(:print) @@ -148,6 +224,8 @@ def parse_statement parse_if elsif peek(:while) parse_while + elsif peek(:switch) + parse_switch elsif peek(:print) parse_print elsif peek(:local) diff --git a/compiler/tokenizer.rb b/compiler/tokenizer.rb index 8fb0f47..8faac0e 100644 --- a/compiler/tokenizer.rb +++ b/compiler/tokenizer.rb @@ -7,11 +7,15 @@ class Tokenizer [:def, /\bcall\b/], [:end, /\bdone\b/], [:if, /\bif\b/], + [:elif, /\belif\b/], + [:else, /\belse\b/], [:while, /\bwhen\b/], [:print, /\bprint\b/], [:return, /\breturn\b/], [:or, /\bor\b/], [:and, /\band\b/], + [:switch, /\bswitch\b/], + [:to, /\bto\b/], #love [:lgraphics, /-G:/], @@ -38,7 +42,7 @@ class Tokenizer [:greater, />/], [:lesser, /=/], - [:lequal, /<=/] + [:lequal, /<=/], [:equal, /=/], [:divide, /\//], [:multiply, /\*/], diff --git a/examples/main.lat b/examples/main.lat index 353af14..67a41fb 100644 --- a/examples/main.lat +++ b/examples/main.lat @@ -4,6 +4,8 @@ nat multiplier = 2 if (-K:isDown("space")) incrementCoin(3) +elif (-K:isDown("w")) + incrementCoin(3) done @@ -16,5 +18,13 @@ when (true) done +switch score + to 10 + print("perfect") + to 5 + print("ok") + +done + print(coins) \ No newline at end of file diff --git a/test.lua b/test.lua index 705d96b..f019ff6 100644 --- a/test.lua +++ b/test.lua @@ -1,8 +1,10 @@ local coins = 250 local incrementVal = 20 local multiplier = 2 -if love.keyboard.isDown("space") then - incrementCoin(3) +if love.keyboard.isDown("space") then +incrementCoin(3) +elseif love.keyboard.isDown("w") then +incrementCoin(3) end function incrementCoin(externalMultiplier) coins = (coins + ((incrementVal * multiplier) * externalMultiplier)) @@ -10,5 +12,10 @@ function incrementCoin(externalMultiplier) end while true do +end +if 10 == score then + print("perfect") +elseif 5 == score then + print("ok") end print(coins) \ No newline at end of file