diff --git a/bin/dhallish b/bin/dhallish index ec2f54dacb64d7dc9d66a287970400c13f9a5fc5..79b947eac1f7fd9d086d2ad223d35e11f3a785a5 100755 --- a/bin/dhallish +++ b/bin/dhallish @@ -31,10 +31,6 @@ ARGV.each { |arg| end } -dhall = Dhallish::Dhallish.new - -time3 = Time.now - if read_from_file.nil? input = $stdin.read else @@ -43,10 +39,10 @@ else file.close end -time4 = Time.now +time3 = Time.now begin - res, type = dhall.evaluate(input) + res, type = Dhallish::evaluate(input) rescue DhallError => err STDERR.puts err exit! 1 @@ -61,10 +57,9 @@ else end end -time5 = Time.now +time4 = Time.now if measure_time puts "" puts "time loading dhallish.rb: #{time2 - time1}" - puts "time creating Dhallish-Instance: #{time3 - time2}" - puts "time for typecheck+evaluate: #{time5 - time4}" + puts "time for typecheck+evaluate: #{time4 - time3}" end diff --git a/lib/DhallishGrammar.treetop b/lib/DhallishGrammar.treetop index e7fb2c3ca40c8a18e8aaeb51eb17b914a285cb73..15bd77efdd16a4c11331d40764afec793db3dc58 100644 --- a/lib/DhallishGrammar.treetop +++ b/lib/DhallishGrammar.treetop @@ -5,13 +5,13 @@ require File.join(File.dirname(__FILE__), 'utils.rb') grammar DhallishGrammar rule root - space? exp:expression space? { def to_node(ctx) exp.to_node(ctx) end } + space? exp:expression space? { def to_node() exp.to_node() end } end rule expression - exp:if_then_else_expression { def to_node(ctx) exp.to_node(ctx) end } / - exp:let_expression { def to_node(ctx) exp.to_node(ctx) end } / - exp:import_alternative_expression { def to_node(ctx) exp.to_node(ctx) end } + exp:if_then_else_expression { def to_node() exp.to_node() end } / + exp:let_expression { def to_node() exp.to_node() end } / + exp:import_alternative_expression { def to_node() exp.to_node() end } end rule eol @@ -41,7 +41,7 @@ grammar DhallishGrammar ## Number Literals rule integer_literal - ("+" / "-") [0-9]+ { def to_node(ctx) Dhallish::Ast::Literal_Node.new(text_value.to_i, Dhallish::Types::Integer) end } + ("+" / "-") [0-9]+ { def to_node() Dhallish::Ast::Literal_Node.new(text_value.to_i, Dhallish::Types::Integer) end } end rule exponent @@ -50,27 +50,27 @@ grammar DhallishGrammar end rule double_literal - ("+" / "-")? [0-9]+ (("." [0-9]+ exponent?) / exponent) { def to_node(ctx) Dhallish::Ast::Literal_Node.new(text_value.to_f, Dhallish::Types::Double) end } + ("+" / "-")? [0-9]+ (("." [0-9]+ exponent?) / exponent) { def to_node() Dhallish::Ast::Literal_Node.new(text_value.to_f, Dhallish::Types::Double) end } end rule natural_literal - [0-9]+ { def to_node(ctx) Dhallish::Ast::Literal_Node.new(text_value.to_i, Dhallish::Types::Natural) end } + [0-9]+ { def to_node() Dhallish::Ast::Literal_Node.new(text_value.to_i, Dhallish::Types::Natural) end } end ## Bools rule bool_literal - "True" { def to_node(ctx) Dhallish::Ast::Literal_Node.new(true, Dhallish::Types::Bool) end } + "True" { def to_node() Dhallish::Ast::Literal_Node.new(true, Dhallish::Types::Bool) end } / - "False" { def to_node(ctx) Dhallish::Ast::Literal_Node.new(false, Dhallish::Types::Bool) end } + "False" { def to_node() Dhallish::Ast::Literal_Node.new(false, Dhallish::Types::Bool) end } end ## Lists rule empty_list_literal "[" space? "]" space? ":" space? "List" space type:expression { - def to_node(ctx) - Dhallish::Ast::ListNode.new [], type.to_node(ctx) + def to_node() + Dhallish::Ast::ListNode.new [], type.to_node() end } end @@ -78,14 +78,14 @@ grammar DhallishGrammar rule non_empty_list_literal "[" space? fst:expression tail:(space? "," space? exp:expression)* space? "]" annot:(space? ":" space? "List" space type:expression)? { - def to_node(ctx) + def to_node() list = [] - list.append fst.to_node(ctx) + list.append fst.to_node() tail.elements.each { |node| - list.append node.exp.to_node(ctx) + list.append node.exp.to_node() } if annot.respond_to? :type - Dhallish::Ast::ListNode.new list, annot.type.to_node(ctx) + Dhallish::Ast::ListNode.new list, annot.type.to_node() else Dhallish::Ast::ListNode.new list, nil end @@ -94,21 +94,21 @@ grammar DhallishGrammar end rule list_literal - exp:empty_list_literal { def to_node(ctx) exp.to_node(ctx) end } / - exp:non_empty_list_literal { def to_node(ctx) exp.to_node(ctx) end } + exp:empty_list_literal { def to_node() exp.to_node() end } / + exp:non_empty_list_literal { def to_node() exp.to_node() end } end ## Records rule record_type_literal - "{" space? "}" { def to_node(ctx) Dhallish::Ast::RecordTypeNode.new({}) end } / + "{" space? "}" { def to_node() Dhallish::Ast::RecordTypeNode.new({}) end } / "{" space? fstkey:label space? ":" space? fstexp:expression tail:(space? "," space? key:label space? ":" space? exp:expression)* space? "}" { - def to_node(ctx) - data = { fstkey.text_value => fstexp.to_node(ctx) } + def to_node() + data = { fstkey.text_value => fstexp.to_node() } tail.elements.each { |node| key = node.key.text_value assert("no key should apeare multiple times in a record: `#{key}`") { !data.key?(key) } - data[key] = node.exp.to_node(ctx) + data[key] = node.exp.to_node() } Dhallish::Ast::RecordTypeNode.new data end @@ -116,15 +116,15 @@ grammar DhallishGrammar end rule record_literal - "{" space? "=" space? "}" { def to_node(ctx) Dhallish::Ast::RecordNode.new({}) end } / + "{" space? "=" space? "}" { def to_node() Dhallish::Ast::RecordNode.new({}) end } / "{" space? fstkey:label space? "=" space? fstexp:expression tail:(space? "," space? key:label space? "=" space? exp:expression)* space? "}" { - def to_node(ctx) - data = { fstkey.text_value => fstexp.to_node(ctx) } + def to_node() + data = { fstkey.text_value => fstexp.to_node() } tail.elements.each { |node| key = node.key.text_value assert("no key should apeare multiple times in a record: `#{key}`") { !data.key?(key) } - data[key] = node.exp.to_node(ctx) + data[key] = node.exp.to_node() } Dhallish::Ast::RecordNode.new data end @@ -135,11 +135,11 @@ grammar DhallishGrammar rule text_literal '"' tail:(exp:('${' space? innerexp:expression space? '}') / esc:('\"') / any:(!'"' .))* '"' { - def to_node(ctx) + def to_node() parts = [] tail.elements.each { |node| if node.respond_to?(:exp) - parts.push node.exp.innerexp.to_node(ctx) + parts.push node.exp.innerexp.to_node() elsif node.respond_to?(:esc) parts.push "\"" else @@ -153,15 +153,15 @@ grammar DhallishGrammar ## Optionals rule optional_literal - prefix:("Some" / "None") space exp:or_expression { def to_node(ctx) Dhallish::Ast::OptionalNode.new prefix.text_value, exp.to_node(ctx) end } + prefix:("Some" / "None") space exp:or_expression { def to_node() Dhallish::Ast::OptionalNode.new prefix.text_value, exp.to_node() end } end ## Type Literals rule forall_literal ("forall" / "∀") space? "(" space? lb:label space? ":" space? type:expression space? ")" space? ("->" / "→") space? res_type:expression { - def to_node(ctx) - Dhallish::Ast::FunctionType.new(type.to_node(ctx), res_type.to_node(ctx), lb.text_value) + def to_node() + Dhallish::Ast::FunctionType.new(type.to_node(), res_type.to_node(), lb.text_value) end } end @@ -170,15 +170,15 @@ grammar DhallishGrammar rule union_literal "<" space? start:(lb:label space? ":" space? type:record_merge_expression space? "|" space?)* lb:label space? "=" space? expr:record_merge_expression tail:(space? "|" space? lb:label space? ":" space? type:record_merge_expression)* space? ">" { - def to_node(ctx) + def to_node() typed_labels = {} start.elements.each { |node| - typed_labels[node.lb.text_value] = node.type.to_node(ctx) + typed_labels[node.lb.text_value] = node.type.to_node() } tail.elements.each { |node| - typed_labels[node.lb.text_value] = node.type.to_node(ctx) + typed_labels[node.lb.text_value] = node.type.to_node() } - Dhallish::Ast::UnionLiteral.new(typed_labels, lb.text_value, expr.to_node(ctx)) + Dhallish::Ast::UnionLiteral.new(typed_labels, lb.text_value, expr.to_node()) end } end @@ -188,13 +188,13 @@ grammar DhallishGrammar end rule union_type_literal - empty_union_type_literal { def to_node(ctx) Dhallish::Ast::UnionType.new({}) end } / + empty_union_type_literal { def to_node() Dhallish::Ast::UnionType.new({}) end } / "<" space? lb:label space? ":" space? type:record_merge_expression tail:(space? "|" space? lb:label space? ":" space? type:record_merge_expression)* space? ">" { - def to_node(ctx) - type_map = {lb.text_value => type.to_node(ctx)} + def to_node() + type_map = {lb.text_value => type.to_node()} tail.elements.each { |node| - type_map[node.lb.text_value] = node.type.to_node(ctx) + type_map[node.lb.text_value] = node.type.to_node() } Dhallish::Ast::UnionType.new(type_map) end @@ -209,9 +209,9 @@ grammar DhallishGrammar rule import_alternative_expression exp:annotated_expression tail:(space? "?" space? alternative:annotated_expression)* { - def to_node(ctx) - tail.elements.reduce(exp.to_node(ctx)) { |tree, node| - Dhallish::Ast::Import_Alternative.new tree, node.alternative.to_node(ctx) + def to_node() + tail.elements.reduce(exp.to_node()) { |tree, node| + Dhallish::Ast::Import_Alternative.new tree, node.alternative.to_node() } end } @@ -220,9 +220,9 @@ grammar DhallishGrammar rule annotated_expression exp:function_type_expression tail:(space? ":" space? type_expr:function_type_expression)* { - def to_node(ctx) - tail.elements.reduce(exp.to_node(ctx)) { |tree, node| - Dhallish::Ast::TypeAnnotationNode.new tree, node.type_expr.to_node(ctx) + def to_node() + tail.elements.reduce(exp.to_node()) { |tree, node| + Dhallish::Ast::TypeAnnotationNode.new tree, node.type_expr.to_node() } end } @@ -231,19 +231,19 @@ grammar DhallishGrammar rule function_type_expression arg_type:or_expression tail:(space? ("->" / "→") space? res_type:or_expression)* { - def to_node(ctx) + def to_node() if tail.elements.size == 0 - arg_type.to_node(ctx) + arg_type.to_node() else tree = nil tail.elements.reverse.each { |node| if tree.nil? - tree = node.res_type.to_node(ctx) + tree = node.res_type.to_node() else - tree = Dhallish::Ast::FunctionType.new node.res_type.to_node(ctx), tree + tree = Dhallish::Ast::FunctionType.new node.res_type.to_node(), tree end } - Dhallish::Ast::FunctionType.new arg_type.to_node(ctx), tree + Dhallish::Ast::FunctionType.new arg_type.to_node(), tree end end } @@ -252,9 +252,9 @@ grammar DhallishGrammar rule or_expression exp:and_expression tail:(space? "||" space? exp:and_expression)* { - def to_node(ctx) - tail.elements.reduce(exp.to_node(ctx)) { |tree, node| - Dhallish::Ast::BinaryArithOpNode.new([Dhallish::Types::Bool], tree, node.exp.to_node(ctx), "||") { |x, y| x || y } + def to_node() + tail.elements.reduce(exp.to_node()) { |tree, node| + Dhallish::Ast::BinaryArithOpNode.new([Dhallish::Types::Bool], tree, node.exp.to_node(), "||") { |x, y| x || y } } end } @@ -263,9 +263,9 @@ grammar DhallishGrammar rule and_expression exp:comparison_expression tail:(space? "&&" space? exp:comparison_expression)* { - def to_node(ctx) - tail.elements.reduce(exp.to_node(ctx)) { |tree, node| - Dhallish::Ast::BinaryArithOpNode.new([Dhallish::Types::Bool], tree, node.exp.to_node(ctx), "&&") { |x, y| x && y } + def to_node() + tail.elements.reduce(exp.to_node()) { |tree, node| + Dhallish::Ast::BinaryArithOpNode.new([Dhallish::Types::Bool], tree, node.exp.to_node(), "&&") { |x, y| x && y } } end } @@ -274,9 +274,9 @@ grammar DhallishGrammar rule comparison_expression exp:add_sub_expression tail:(space? op:("==" / "!=" / "<=" / "<" / ">=" / ">") space? exp:add_sub_expression)* { - def to_node(ctx) - tail.elements.reduce(exp.to_node(ctx)) { |tree, node| - Dhallish::Ast::ComparisonOpNode.new(tree, node.exp.to_node(ctx), node.op.text_value) { |lhs_val, rhs_val| lhs_val.send(node.op.text_value, rhs_val )} + def to_node() + tail.elements.reduce(exp.to_node()) { |tree, node| + Dhallish::Ast::ComparisonOpNode.new(tree, node.exp.to_node(), node.op.text_value) { |lhs_val, rhs_val| lhs_val.send(node.op.text_value, rhs_val )} } end } @@ -285,9 +285,9 @@ grammar DhallishGrammar rule add_sub_expression exp:mult_div_expression tail:(space? op:("+"/"-") space? exp:mult_div_expression)* { - def to_node(ctx) - tail.elements.reduce(exp.to_node(ctx)) { |tree, node| - exp = node.exp.to_node(ctx) + def to_node() + tail.elements.reduce(exp.to_node()) { |tree, node| + exp = node.exp.to_node() if node.op.text_value == "+" Dhallish::Ast::BinaryArithOpNode.new(Dhallish::Types::Numbers, tree, exp, "+") { |x, y| x + y } else @@ -301,9 +301,9 @@ grammar DhallishGrammar rule mult_div_expression exp:list_concat_expression tail:(space? op:("*"/"/") space? exp:list_concat_expression)* { - def to_node(ctx) - tail.elements.reduce(exp.to_node(ctx)) { |tree, node| - exp = node.exp.to_node(ctx) + def to_node() + tail.elements.reduce(exp.to_node()) { |tree, node| + exp = node.exp.to_node() if node.op.text_value == "*" Dhallish::Ast::BinaryArithOpNode.new(Dhallish::Types::Numbers, tree, exp, "*") { |x, y| x * y } else @@ -318,9 +318,9 @@ grammar DhallishGrammar rule list_concat_expression exp:text_append_expression tail:(space? "#" space? exp:text_append_expression)* { - def to_node(ctx) - tail.elements.reduce(exp.to_node(ctx)) { |tree, node| - Dhallish::Ast::ListConcatNode.new(tree, node.exp.to_node(ctx)) + def to_node() + tail.elements.reduce(exp.to_node()) { |tree, node| + Dhallish::Ast::ListConcatNode.new(tree, node.exp.to_node()) } end } @@ -329,9 +329,9 @@ grammar DhallishGrammar rule text_append_expression exp:record_merge_expression tail:(space? "++" space? exp:record_merge_expression)* { - def to_node(ctx) - tail.elements.reduce(exp.to_node(ctx)) { |tree, node| - Dhallish::Ast::BinaryArithOpNode.new([Dhallish::Types::Text], tree, node.exp.to_node(ctx), "+") { |x, y| x + y } + def to_node() + tail.elements.reduce(exp.to_node()) { |tree, node| + Dhallish::Ast::BinaryArithOpNode.new([Dhallish::Types::Text], tree, node.exp.to_node(), "+") { |x, y| x + y } } end } @@ -340,14 +340,14 @@ grammar DhallishGrammar rule record_merge_expression exp:application_expression tail:(space? op:("//\\\\" / "⩓" / "/\\" / "∧" / "//" / "⫽") space? exp:application_expression)* { - def to_node(ctx) - tail.elements.reduce(exp.to_node(ctx)) { |tree, node| + def to_node() + tail.elements.reduce(exp.to_node()) { |tree, node| if node.op.text_value == "//\\\\" or node.op.text_value == "⩓" - Dhallish::Ast::RecordTypeRecursiveMergeNode.new tree, node.exp.to_node(ctx) + Dhallish::Ast::RecordTypeRecursiveMergeNode.new tree, node.exp.to_node() elsif node.op.text_value == "/\\" or node.op.text_value == "∧" - Dhallish::Ast::RecordRecursiveMergeNode.new tree, node.exp.to_node(ctx) + Dhallish::Ast::RecordRecursiveMergeNode.new tree, node.exp.to_node() else - Dhallish::Ast::RecordNonRecursiveMergeNode.new tree, node.exp.to_node(ctx) + Dhallish::Ast::RecordNonRecursiveMergeNode.new tree, node.exp.to_node() end } end @@ -357,9 +357,9 @@ grammar DhallishGrammar rule application_expression fn:proj_sel_expression tail:(space? exp:(!reserved arg:proj_sel_expression))* { - def to_node(ctx) - tail.elements.reduce(fn.to_node(ctx)) { |tree, node| - Dhallish::Ast::FunctionCallNode.new(tree, node.exp.arg.to_node(ctx)) + def to_node() + tail.elements.reduce(fn.to_node()) { |tree, node| + Dhallish::Ast::FunctionCallNode.new(tree, node.exp.arg.to_node()) } end } @@ -381,8 +381,8 @@ grammar DhallishGrammar rule proj_sel_expression pe:primitive_expression tail:(space? "." space? sel:(a:label / b:key_list))* { - def to_node(ctx) - tail.elements.reduce(pe.to_node(ctx)) { |tree, node| + def to_node() + tail.elements.reduce(pe.to_node()) { |tree, node| if node.sel.respond_to? :a Dhallish::Ast::RecordUnionSelector.new tree, node.sel.a.text_value else @@ -394,23 +394,23 @@ grammar DhallishGrammar end rule primitive_expression - exp:bool_literal { def to_node(ctx) exp.to_node(ctx) end } / - exp:double_literal { def to_node(ctx) exp.to_node(ctx) end } / - exp:natural_literal { def to_node(ctx) exp.to_node(ctx) end } / - exp:integer_literal { def to_node(ctx) exp.to_node(ctx) end } / - exp:text_literal { def to_node(ctx) exp.to_node(ctx) end } / - exp:list_literal { def to_node(ctx) exp.to_node(ctx) end } / - exp:function_definition { def to_node(ctx) exp.to_node(ctx) end } / - exp:optional_literal { def to_node(ctx) exp.to_node(ctx) end } / - exp:forall_literal { def to_node(ctx) exp.to_node(ctx) end } / - exp:import_expression { def to_node(ctx) exp.to_node(ctx) end } / - exp:label { def to_node(ctx) exp.to_node(ctx) end } / - exp:record_literal { def to_node(ctx) exp.to_node(ctx) end } / - exp:record_type_literal { def to_node(ctx) exp.to_node(ctx) end } / - exp:union_literal { def to_node(ctx) exp.to_node(ctx) end } / - exp:union_type_literal { def to_node(ctx) exp.to_node(ctx) end } / - "(" space? exp:expression space? ")" { def to_node(ctx) exp.to_node(ctx) end } / - "???" { def to_node(ctx) Dhallish::Ast::GetContext.new end } + exp:bool_literal { def to_node() exp.to_node() end } / + exp:double_literal { def to_node() exp.to_node() end } / + exp:natural_literal { def to_node() exp.to_node() end } / + exp:integer_literal { def to_node() exp.to_node() end } / + exp:text_literal { def to_node() exp.to_node() end } / + exp:list_literal { def to_node() exp.to_node() end } / + exp:function_definition { def to_node() exp.to_node() end } / + exp:optional_literal { def to_node() exp.to_node() end } / + exp:forall_literal { def to_node() exp.to_node() end } / + exp:import_expression { def to_node() exp.to_node() end } / + exp:label { def to_node() exp.to_node() end } / + exp:record_literal { def to_node() exp.to_node() end } / + exp:record_type_literal { def to_node() exp.to_node() end } / + exp:union_literal { def to_node() exp.to_node() end } / + exp:union_type_literal { def to_node() exp.to_node() end } / + "(" space? exp:expression space? ")" { def to_node() exp.to_node() end } / + "???" { def to_node() Dhallish::Ast::GetContext.new end } end ## End of operator expressions @@ -420,30 +420,30 @@ grammar DhallishGrammar "then" space exp_true:expression space "else" space exp_false:expression { - def to_node(ctx) - Dhallish::Ast::IfThenElseNode.new cond.to_node(ctx), exp_true.to_node(ctx), exp_false.to_node(ctx) + def to_node() + Dhallish::Ast::IfThenElseNode.new cond.to_node(), exp_true.to_node(), exp_false.to_node() end } end rule label - ("_" / [a-zA-Z]) ("_" / "-" / "/" / [a-zA-Z0-9])* { def to_node(ctx) Dhallish::Ast::VariableNode.new text_value end } / - "`" lb:(([a-zA-Z0-9] / "-" / "/" / "_" / ":" / "." / "$")+) "`" { def to_node(ctx) Dhallish::Ast::VariableNode.new lb.text_value end } + ("_" / [a-zA-Z]) ("_" / "-" / "/" / [a-zA-Z0-9])* { def to_node() Dhallish::Ast::VariableNode.new text_value end } / + "`" lb:(([a-zA-Z0-9] / "-" / "/" / "_" / ":" / "." / "$")+) "`" { def to_node() Dhallish::Ast::VariableNode.new lb.text_value end } end rule let_expression declarations:("let" space var:label space? annot:(":" space? exp:expression space?)? "=" space? val:expression space)+ "in" space in_expr:expression { - def to_node(ctx) + def to_node() vars = [] declarations.elements.each { |node| typeannot = nil if node.respond_to? :annot and node.annot.respond_to? :exp - typeannot = node.annot.exp.to_node(ctx) + typeannot = node.annot.exp.to_node() end - vars.append [node.var.text_value, typeannot, node.val.to_node(ctx)] + vars.append [node.var.text_value, typeannot, node.val.to_node()] } - Dhallish::Ast::LetInNode.new vars, in_expr.to_node(ctx) + Dhallish::Ast::LetInNode.new vars, in_expr.to_node() end } end @@ -451,8 +451,8 @@ grammar DhallishGrammar rule function_definition ("\\" / "λ") space? "(" space? lb:label space? ":" space? type_exp:expression space? ")" space? ("->" / "→") space? exp:expression { - def to_node(ctx) - Dhallish::Ast::FunctionDefinitionNode.new lb.text_value, type_exp.to_node(ctx), exp.to_node(ctx) + def to_node() + Dhallish::Ast::FunctionDefinitionNode.new lb.text_value, type_exp.to_node(), exp.to_node() end } end @@ -473,7 +473,7 @@ grammar DhallishGrammar rule import_expression prefix:("../" / "./" / "~/" / "env:" / "http:" / "https:") src:import_source as_type:(space "as" space import_type:"Text")? { - def to_node(ctx) + def to_node() import_as_text = (as_type.respond_to? :import_type and as_type.import_type.text_value == "Text") Dhallish::Ast::Import.new prefix.text_value, src.text_value, import_as_text end diff --git a/lib/ast.rb b/lib/ast.rb index 39817011a9e12568504b68fce7ce2cf41623fbfe..66a40061e919863a6c0019ea0c731e5568a287ac 100644 --- a/lib/ast.rb +++ b/lib/ast.rb @@ -433,11 +433,11 @@ module Dhallish def compute_type(ctx) rectype = @rec.compute_type ctx - assert("`.` can only be used on records and unions, the key `#{@key}` must exist") { + assert("`.` can only be used on records and unions, the key `#{@key}` must exist") { ((rectype.is_a? Types::Record or rectype.is_a? Types::Union) and !rectype.types[@key].nil?) \ or (rectype.is_a? Types::Type and rectype.metadata.is_a? Types::Union) } - if rectype.is_a? Types::Union + if rectype.is_a? Types::Union Types::Optional.new rectype.types[@key] elsif rectype.is_a? Types::Record rectype.types[@key] @@ -630,7 +630,7 @@ module Dhallish else src = @src if prefix == "./" or prefix == "../" - basedir = ctx["#DIR#"] + basedir = ctx["<#DIR#>"] if basedir.is_a? String src = File.join basedir , (@prefix + src) new_path = File.dirname src @@ -665,8 +665,7 @@ module Dhallish Types::Text else # treat as dhallish expression - d = Dhallish.new new_path - @buf, type = d.evaluate text + @buf, type = Dhallish::evaluate(text, Dhallish::empty_context(new_path)) type end end @@ -792,7 +791,7 @@ module Dhallish Types::Record.new({}) end - def evaluate(ctx) { "#valctx#" => ctx, "#typectx#" => @typectx } end + def evaluate(ctx) { "<#TYPES#>" => @typectx, "<#VALS#>" => ctx } end end end diff --git a/lib/dhallish.rb b/lib/dhallish.rb index 5c9025b69ea8cba5b957a11636a91db9723d64fb..36638412e8fe461f87b88b5a7b4913c8e7f4d41f 100644 --- a/lib/dhallish.rb +++ b/lib/dhallish.rb @@ -15,76 +15,56 @@ end module Dhallish - class Dhallish - attr_accessor :context - attr_accessor :typectx - attr_accessor :basedir + @@parser = DhallishGrammarParser.new - def initialize(basedir=nil) - if basedir.nil? - basedir = Dir.pwd - end - @parser = DhallishGrammarParser.new - @context = Context.new # for values used in `astnode.evaluate` - @typectx = Context.new # for type-informations used in `compute_type` - @typectx["#DIR#"] = basedir # `#` is not allowed in dhallish-identifiers, so this is should be fine - ::Dhallish::fill_context(@context, @typectx) - end - - def evaluate_file(file, ctx = @context, typectx = @typectx) - file = File.open(file) - res = evaluate(file.read, ctx, typectx) - file.close - res - end + def empty_context(basedir=Dir.pwd) + ctx = { "<#TYPES#>" => Context.new, "<#VALS#>" => Context.new } + ctx["<#TYPES#>"]["<#DIR#>"] = basedir + fill_context(ctx["<#VALS#>"], ctx["<#TYPES#>"]) + ctx + end + module_function :empty_context - def evaluate(dhallcode, ctx = @context, typectx = @typectx) - treetopast = @parser.parse dhallcode - if treetopast.nil? - raise DhallError, "#{@parser.failure_reason} (line/column: #{@parser.failure_line}:#{@parser.failure_column})" - end + def evaluate(dhallcode, ctx=nil, expected_type=nil) + if ctx.nil?; ctx = empty_context() end - ast = treetopast.to_node nil - type = ast.compute_type typectx + rawast = @@parser.parse dhallcode + ast = rawast.to_node - return [ast.evaluate(ctx), type] + if ast.nil? + raise DhallError, "#{@parser.failure_reason} (line/column: #{@parser.failure_line}:#{@parser.failure_column})" end - def create_ctx_from_file(file) - file = File.open(file) - res = create_ctx(file.read) - file.close - res - end + type = ast.compute_type ctx["<#TYPES#>"] + res = ast.evaluate ctx["<#VALS#>"] - def create_ctx(dhallcode) - val, type = evaluate(dhallcode, @context, @typectx) - if !type.is_a? Types::Record or val["#valctx#"].nil? or val["#typectx#"].nil? - raise DhallError, "Dhallish: create_ctx did not return a context! use `???` as a return expression in dhallish for create_ctx" + if !expected_type.nil? + if type != expected_type + raise DhallError, "expression return type missmatch: expected `#{expected_type}`, got: `#{type}`" + else + res end - val + else + [res, type] end + end + module_function :evaluate - def evaluate_in_ctx_from_file(file, dhallctx, expected_type=nil) - file = File.open(file) - res = evaluate_in_ctx(file.read, dhallctx, expected_type) - file.close - res - end - - def evaluate_in_ctx(dhallcode, dhallctx, expected_type=nil) - if !dhallctx.is_a? Hash or dhallctx["#valctx#"].nil? or dhallctx["#typectx#"].nil? - raise DhallError, "Dhallish: evaluate_in_ctx must be called with a context returned by create_ctx" - end - typectx = dhallctx["#typectx#"] - valctx = dhallctx["#valctx#"] - - val, type = evaluate(dhallcode, valctx, typectx) - if expected_type != nil - assert("return type missmatch of `evaluate_in_ctx`") { type == expected_type } - end - val + def create_ctx(dhallcode, basedir=Dir.pwd) + empty_ctx = empty_context(basedir) + ctx, type = evaluate(dhallcode, empty_ctx) + if type != Types::Record.new({}) or ctx["<#TYPES#>"].nil? or ctx["<#VALS#>"].nil? + raise DhallError, "return type of dhallcode supplied to `create_ctx` did not return a context (but something of type `#{type}`). use `???`" end + ctx end + module_function :create_ctx + def create_ctx_from_file(dhallfile, basedir=nil) + if basedir.nil?; basedir = File.dirname(dhallfile) end + file = File.open(dhallfile) + res = create_ctx(file.read, basedir) + file.close + res + end end diff --git a/lib/stdlib.rb b/lib/stdlib.rb index 3371d0fd8da8c95a21d31f60164844d61c2ac38b..cf5b5a72ddb61f12816c303eb76028996df94e91 100644 --- a/lib/stdlib.rb +++ b/lib/stdlib.rb @@ -157,7 +157,7 @@ module Dhallish globalctx["List/build"] = BuiltinFunction.new { |a| BuiltinFunction.new { |f| cons = BuiltinFunction.new { |x| - BuiltinFunction.new { |list| [x] + list } + BuiltinFunction.new { |list| list + [x] } } f.call(Types::List.new(a)).call(cons).call([]) } diff --git a/lib/types.rb b/lib/types.rb index bd636f1b64ca6174234361e19f45a62c4aaaf1aa..1e6bbee26f4eacf1214c09402f6369345a34d9c5 100644 --- a/lib/types.rb +++ b/lib/types.rb @@ -283,6 +283,10 @@ module Dhallish module_function :is_a_type? Numbers = [Natural, Integer, Double] + TextList = List.new(Text) + NaturalList = List.new(Natural) + IntegerList = List.new(Integer) + DoubleList = List.new(Double) end def to_json(dhallval) diff --git a/tests/test.rb b/tests/test.rb index 28df652c23f4cb8c223dc79464c4dea4929194ec..bbeb9dc7d215c74dba9131e11a4e69fe59924640 100755 --- a/tests/test.rb +++ b/tests/test.rb @@ -41,7 +41,7 @@ positive_tests = { negative_tests = { "Undefined Variable": "let x = 1 in x + y", "badly typed list": "[10, +10]", - "recursive function definition": "let f = \\(n : Natural) -> f n", + "recursive function definition": "let f = \\(n : Natural) -> f n in f 42", "Literal type annotation mismatch": "+42 : Natural", "Let..in type annotation mismatch": "let x : Natural = 10.0 in x", "function call argtype mismatch": "let f = \\(x : Double) -> x * 10e10 in f 5", @@ -54,8 +54,7 @@ positive_tests.each { |name, arr| code, expected = arr begin - dhallish = Dhallish::Dhallish.new - res = (dhallish.evaluate code)[0] + res, type = Dhallish::evaluate(code) assert("Testing Dhallish: `#{code}`") { res == expected } rescue print_msg(name, false) @@ -69,8 +68,7 @@ negative_tests.each { |name, arr| code = arr begin - dhallish = Dhallish::Dhallish.new - dhallish.evaluate code + Dhallish::evaluate(code) rescue print_msg(name, true) else @@ -89,8 +87,7 @@ dhallfiles.each { |file| expected_file_name = file.sub '.dhall', "_expected.json" expected = JSON.parse(`cat #{expected_file_name}`) - dhallish = Dhallish::Dhallish.new - val = (dhallish.evaluate `cat #{file}`)[0] + val, type = (Dhallish::evaluate `cat #{file}`) result = JSON.parse(Dhallish::to_json val) assert("Testing Dhall-Compability for `#{file}`") { expected == result } rescue @@ -108,8 +105,7 @@ dhallfiles.each { |file| expected_file_name = file.sub '.dhallish', "_expected.json" expected = JSON.parse(`cat #{expected_file_name}`) - dhallish = Dhallish::Dhallish.new - val = (dhallish.evaluate `cat #{file}`)[0] + val, type = (Dhallish::evaluate `cat #{file}`) result = JSON.parse(Dhallish::to_json val) assert("Testing Dhall-Compability for `#{file}`") { expected == result } rescue diff --git a/tests/test_dhallish_ctx.rb b/tests/test_dhallish_ctx.rb index bff3cd5c35d51a33ca145d5749ca6866f43863b6..fdd0e127bcc6958169d9b560f7a57337322952fb 100644 --- a/tests/test_dhallish_ctx.rb +++ b/tests/test_dhallish_ctx.rb @@ -1,13 +1,11 @@ require_relative '../lib/dhallish.rb' -dhall = Dhallish::Dhallish.new - -ctx = dhall.create_ctx(" +ctx = Dhallish::create_ctx(" let x = 41 let f = \\(n: Natural) -> n + 1 in ??? ") -res = dhall.evaluate_in_ctx("f x", ctx) +res = Dhallish::evaluate("f x", ctx, Dhallish::Types::Natural) puts res