Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP
Browse files

Loops and switch/case: eg/cond.js works again.

  • Loading branch information...
commit b69f0a66256d7cd08d83c7aab55ce99bdb9d3985 1 parent 7453963
@matthewd authored
View
42 lib/capuchin/nodes.rb
@@ -70,12 +70,30 @@ def initialize(value, arguments)
end
class NewExprNode < FunctionCallNode; end
+class BreakNode < Node
+ attr_accessor :value
+ def initialize(value)
+ @value = value
+ end
+end
+class ContinueNode < Node
+ attr_accessor :value
+ def initialize(value)
+ @value = value
+ end
+end
class ReturnNode < Node
attr_accessor :value
def initialize(value)
@value = value
end
end
+class ThrowNode < Node
+ attr_accessor :value
+ def initialize(value)
+ @value = value
+ end
+end
class ExpressionStatementNode < Node
attr_accessor :value
def initialize(value)
@@ -163,6 +181,12 @@ def initialize(conditions, value, else_)
end
end
+class VarStatementNode < Node
+ attr_accessor :value
+ def initialize(value)
+ @value = value
+ end
+end
class VarDeclNode < Node
attr_accessor :name, :value, :const
def initialize(name, value, const=false)
@@ -176,12 +200,30 @@ def initialize(name, value)
end
end
+class ForNode < Node
+ attr_accessor :init, :test, :counter, :value
+ def initialize(init, test, counter, value)
+ @init, @test, @counter, @value = init, test, counter, value
+ end
+end
class IfNode < Node
attr_accessor :conditions, :value, :else
def initialize(conditions, value, else_)
@conditions, @value, @else = conditions, value, else_
end
end
+class SwitchNode < Node
+ attr_accessor :left, :value
+ def initialize(left, value)
+ @left, @value = left, value
+ end
+end
+class CaseClauseNode < Node
+ attr_accessor :left, :value
+ def initialize(left, value)
+ @left, @value = left, value
+ end
+end
class BlockNode < Node
attr_accessor :statements
def initialize(statements)
View
33 lib/capuchin/parser.rb
@@ -85,6 +85,8 @@ class Capuchin::ASTBuilder < Parslet::Transform
rule(:binary => ',', :right => simple(:right)) { Capuchin::Nodes::CommaNode.new(nil, right) }
rule(:var => simple(:var), :init => simple(:init)) { Capuchin::Nodes::VarDeclNode.new(var, init) }
+ rule(:vars => simple(:var)) { Capuchin::Nodes::VarStatementNode.new([var]) }
+ rule(:vars => sequence(:vars)) { Capuchin::Nodes::VarStatementNode.new(vars) }
rule(:expr_statement => simple(:expr)) { Capuchin::Nodes::ExpressionStatementNode.new(expr) }
rule(:statement => simple(:statement)) { statement }
@@ -109,10 +111,21 @@ class Capuchin::ASTBuilder < Parslet::Transform
rule(:call => { :args => simple(:arg) }) { Capuchin::Nodes::FunctionCallNode.new(nil, arg ? [arg] : []) }
rule(:call => { :args => sequence(:args) }) { Capuchin::Nodes::FunctionCallNode.new(nil, args) }
+ rule(:break => simple(:value)) { Capuchin::Nodes::BreakNode.new(value) }
+ rule(:continue => simple(:value)) { Capuchin::Nodes::ContinueNode.new(value) }
rule(:return => simple(:value)) { Capuchin::Nodes::ReturnNode.new(value) }
+ rule(:throw => simple(:value)) { Capuchin::Nodes::ThrowNode.new(value) }
- #rule(:block => sequence(:statements)) { Capuchin::Nodes::BlockNode.new(statements) }
+ rule(:label => simple(:label), :labelled => simple(:statement)) { Capuchin::Nodes::LabelNode.new(label, statement) }
+
+ rule(:block => sequence(:statements)) { Capuchin::Nodes::BlockNode.new(statements) }
rule(:if_condition => simple(:cond), :true_part => simple(:t), :false_part => simple(:f)) { Capuchin::Nodes::IfNode.new(cond, t, f) }
+
+ rule(:case => simple(:value), :code => sequence(:code)) { Capuchin::Nodes::CaseClauseNode.new(value, code) }
+ rule(:default => 'default', :code => sequence(:code)) { Capuchin::Nodes::CaseClauseNode.new(nil, code) }
+ rule(:switch_statement => { :switch => simple(:value), :cases => sequence(:options) }) { Capuchin::Nodes::SwitchNode.new(value, options) }
+
+ rule(:init => simple(:init), :test => simple(:cond), :counter => simple(:counter), :code => simple(:code)) { Capuchin::Nodes::ForNode.new(init, cond, counter, code) }
end
class Capuchin::Parser < Parslet::Parser
@@ -413,7 +426,7 @@ class Capuchin::Parser < Parslet::Parser
end
rule(:variable_statement) do
- `var` >> sp >> variable_declaration_list >> sp? >> (`;` | error)
+ `var` >> sp >> variable_declaration_list.as(:vars) >> sp? >> (`;` | error)
end
rule(:variable_declaration_list) do
@@ -453,13 +466,13 @@ class Capuchin::Parser < Parslet::Parser
end
rule(:iteration_statement) do
- `do` >> sp? >> statement >> sp? >> `while` >> sp? >> `(` >> sp? >> expr >> sp? >> `)` >> sp? >> (`;` | error) |
- `while` >> sp? >> `(` >> sp? >> expr >> sp? >> `)` >> sp? >> statement |
- `for` >> sp? >> `(` >> sp? >> (expr_no_in >> sp?).maybe >> `;` >> sp? >> (expr >> sp?).maybe >> `;` >> sp? >> (expr >> sp?).maybe >> `)` >> sp? >> statement |
- `for` >> sp? >> `(` >> sp? >> `var` >> sp >> variable_declaration_list_no_in >> sp? >> `;` >> sp? >> (expr >> sp?).maybe >> `;` >> sp? >> (expr >> sp?).maybe >> `)` >> sp? >> statement |
- `for` >> `(` >> left_hand_side_expr >> sp >> `in` >> sp >> (expr >> sp?).maybe >> `)` >> sp? >> statement |
- `for` >> `(` >> `var` >> sp >> ident >> sp >> `in` >> sp >> (expr >> sp?).maybe >> `)` >> sp? >> statement |
- `for` >> `(` >> `var` >> sp >> ident >> sp? >> `=` >> sp? >> assignment_expr_no_in >> sp >> `in` >> sp >> (expr >> sp?).maybe >> `)` >> sp? >> statement
+ `do` >> sp? >> statement.as(:code) >> sp? >> `while` >> sp? >> `(` >> sp? >> expr.as(:do_while) >> sp? >> `)` >> sp? >> (`;` | error) |
+ `while` >> sp? >> `(` >> sp? >> expr.as(:while) >> sp? >> `)` >> sp? >> statement.as(:code) |
+ `for` >> sp? >> `(` >> sp? >> (expr_no_in >> sp?).maybe.as(:init) >> `;` >> sp? >> (expr >> sp?).maybe.as(:test) >> `;` >> sp? >> (expr >> sp?).maybe.as(:counter) >> `)` >> sp? >> statement.as(:code) |
+ `for` >> sp? >> `(` >> sp? >> (`var` >> sp >> variable_declaration_list_no_in.as(:vars)).as(:init) >> sp? >> `;` >> sp? >> (expr >> sp?).maybe.as(:test) >> `;` >> sp? >> (expr >> sp?).maybe.as(:counter) >> `)` >> sp? >> statement.as(:code) |
+ `for` >> sp? >> `(` >> sp? >> (left_hand_side_expr.as(:left) >> sp >> `in` >> sp >> (expr >> sp?).maybe.as(:right)).as(:for_in) >> `)` >> sp? >> statement.as(:code) |
+ `for` >> sp? >> `(` >> sp? >> ((`var` >> sp >> ident.as(:var)).as(:vars) >> sp >> `in` >> sp >> (expr >> sp?).maybe.as(:right)).as(:for_in) >> `)` >> sp? >> statement.as(:code) |
+ `for` >> sp? >> `(` >> sp? >> ((`var` >> sp >> ident.as(:var) >> sp? >> `=` >> sp? >> assignment_expr_no_in.as(:expr)).as(:vars) >> sp >> `in` >> sp >> (expr >> sp?).maybe.as(:right)).as(:for_in) >> `)` >> sp? >> statement.as(:code)
end
rule(:continue_statement) do
@@ -491,7 +504,7 @@ class Capuchin::Parser < Parslet::Parser
end
rule(:labelled_statement) do
- ident.as(:label) >> sp? >> `:` >> sp? >> statement
+ ident.as(:label) >> sp? >> `:` >> sp? >> statement.as(:labelled)
end
rule(:throw_statement) do
View
14 lib/capuchin/visitor.rb
@@ -39,6 +39,15 @@ def visit_VarDeclNode(o)
name = o.name.to_sym
@scope.add_variable name, o
end
+ def visit_ForNode(o)
+ accept o.init if Capuchin::Nodes::VarStatementNode === o.init
+ end
+ def visit_ForInNode(o)
+ accept o.init if Capuchin::Nodes::VarStatementNode === o.init
+ end
+ def visit_VarStatementNode(o)
+ accept o.value
+ end
def visit_FunctionDeclNode(o)
name = o.value.to_sym
@scope.add_variable name, o
@@ -276,6 +285,9 @@ def compile_method(line, name, arguments, body)
meth
end
+ def visit_VarStatementNode(o)
+ accept o.value
+ end
def visit_VarDeclNode(o)
var = @g.state.scope.variables[o.name.to_sym]
if o.value
@@ -472,7 +484,7 @@ def visit_SwitchNode(o)
accept o.left
pos(o)
- if cases = o.value.value
+ if cases = o.value
has_default = false
cases = cases.map {|c| [c, @g.new_label] }
cases.each do |(c,code)|
Please sign in to comment.
Something went wrong with that request. Please try again.