diff --git a/app/elm/Compiler/Ast.elm b/app/elm/Compiler/Ast.elm index 3cb16db..53b7788 100644 --- a/app/elm/Compiler/Ast.elm +++ b/app/elm/Compiler/Ast.elm @@ -3,6 +3,7 @@ module Compiler.Ast exposing , CompiledProgram , Context(..) , Function + , Macro , Node(..) , Program , compile @@ -45,6 +46,13 @@ type alias Function = } +type alias Macro = + { name : String + , requiredArguments : List String + , body : List Node + } + + {-| Represent a compiled function. -} type alias CompiledFunction = diff --git a/app/elm/Compiler/Parser.elm b/app/elm/Compiler/Parser.elm index afa0c6e..939c06b 100644 --- a/app/elm/Compiler/Parser.elm +++ b/app/elm/Compiler/Parser.elm @@ -6,6 +6,7 @@ module Compiler.Parser exposing , booleanExpression , defaultState , functionDefinition + , macroDefinition , output , statement , term @@ -235,6 +236,37 @@ functionBody_ state acc = ] +defineMacro : State -> Ast.Macro -> Parser Ast.Macro +defineMacro state newMacro = + functionBody state + |> P.map (\body -> { newMacro | body = body }) + + +macroDefinition : State -> Parser Ast.Macro +macroDefinition state = + P.inContext MacroDefinition <| + (macroHeader + |> P.andThen (defineMacro state) + ) + + +macroHeader : Parser Ast.Macro +macroHeader = + P.succeed Ast.Macro + |. Helper.keyword ".macro" + |. Helper.spaces + |= Helper.functionName + |= P.oneOf + [ P.succeed identity + |. P.backtrackable Helper.spaces + |= requiredArguments + , P.succeed [] + ] + |. Helper.maybeSpaces + |. Helper.symbol "\n" + |= P.succeed [] + + line : State -> Parser (List Ast.Node) line state = P.inContext Line <| diff --git a/app/elm/Compiler/Parser/Context.elm b/app/elm/Compiler/Parser/Context.elm index ad98ab3..38f613e 100644 --- a/app/elm/Compiler/Parser/Context.elm +++ b/app/elm/Compiler/Parser/Context.elm @@ -6,6 +6,7 @@ type Context | Toplevel | FunctionDefinition | FunctionBody + | MacroDefinition | Line | Statements | Statement diff --git a/tests/Test/Parser.elm b/tests/Test/Parser.elm index 62a2144..c073bdf 100644 --- a/tests/Test/Parser.elm +++ b/tests/Test/Parser.elm @@ -119,6 +119,46 @@ functionDefinition = ] +parsesMacro : String -> Ast.Macro -> Expectation +parsesMacro source macro = + let + result = + Parser.run (Parser.macroDefinition defaultState) source + in + Expect.equal result (Ok macro) + + +macroDefinition : Test +macroDefinition = + describe "define a macro" <| + [ test "with mandatory arguments and no body" <| + \_ -> + parsesMacro ".macro foo :bar :baz\nend\n" + { name = "foo" + , requiredArguments = [ "bar", "baz" ] + , body = [] + } + , test "with mandatory argument and body" <| + \_ -> + parsesMacro ".macro foo :bar\nprint :bar\nend\n" + { name = "foo" + , requiredArguments = [ "bar" ] + , body = + [ Ast.CommandN + { name = "print", f = C.printN, numberOfDefaultArguments = 1 } + [ Ast.Variable "bar" ] + ] + } + , test "without arguments" <| + \_ -> + parsesMacro ".macro foo\nend\n" + { name = "foo" + , requiredArguments = [] + , body = [] + } + ] + + parsesArithmeticExpression : String -> Test parsesArithmeticExpression expression = let