diff --git a/app/elm/Compiler/Ast.elm b/app/elm/Compiler/Ast.elm index afc7955..2fe2776 100644 --- a/app/elm/Compiler/Ast.elm +++ b/app/elm/Compiler/Ast.elm @@ -107,6 +107,7 @@ type Node | Run Node | Make Node Node | Localmake Node Node + | Local Node | Thing Node | Variable String | Value Type.Value @@ -234,6 +235,9 @@ typeOfCallee node = Localmake _ _ -> Command { name = "localmake" } + Local _ -> + Command { name = "local" } + Thing _ -> Primitive { name = "thing" } @@ -881,6 +885,12 @@ compile context node = ] |> List.concat + Local name -> + [ compileInContext (Expression { caller = "local" }) name + , [ Instruction.Local ] + ] + |> List.concat + Thing name -> [ compileInContext (Expression { caller = "thing" }) name , [ Instruction.Thing ] diff --git a/app/elm/Compiler/Parser.elm b/app/elm/Compiler/Parser.elm index 50227bf..d1c7371 100644 --- a/app/elm/Compiler/Parser.elm +++ b/app/elm/Compiler/Parser.elm @@ -374,6 +374,7 @@ statement state = , P.lazy (\_ -> run state) , stop , localmake state + , local state , make state , templateVariable , thing state @@ -800,6 +801,16 @@ localmake state = ) +local : State -> Parser Ast.Node +local state = + P.inContext Local <| + (P.succeed Ast.Local + |. Helper.keyword "local" + |. Helper.spaces + |= booleanExpression state + ) + + make : State -> Parser Ast.Node make state = P.inContext Make <| diff --git a/app/elm/Compiler/Parser/Context.elm b/app/elm/Compiler/Parser/Context.elm index 38f613e..fd2c3a0 100644 --- a/app/elm/Compiler/Parser/Context.elm +++ b/app/elm/Compiler/Parser/Context.elm @@ -17,6 +17,7 @@ type Context | InParentheses | TemplateVariable | Localmake + | Local | Make | Thing | Variable diff --git a/app/elm/Vm/Instruction.elm b/app/elm/Vm/Instruction.elm index 7ea2576..b9f05ce 100644 --- a/app/elm/Vm/Instruction.elm +++ b/app/elm/Vm/Instruction.elm @@ -30,6 +30,7 @@ type Instruction | LocalVariable String | Make | Localmake + | Local | Thing | Introspect0 I.Introspect0 | Introspect1 I.Introspect1 diff --git a/app/elm/Vm/Vm.elm b/app/elm/Vm/Vm.elm index 518d4d7..4155778 100644 --- a/app/elm/Vm/Vm.elm +++ b/app/elm/Vm/Vm.elm @@ -124,6 +124,9 @@ encodeInstruction instruction = Localmake -> "Localmake" + Local -> + "Local" + Thing -> "Thing" @@ -858,6 +861,27 @@ localmake vm = ) +local : Vm -> Result Error Vm +local vm = + popValue1 vm + |> Result.andThen + (\( name, newVm ) -> + name + |> Type.toWord + |> Result.map + (\word -> + let + newScopes = + vm.scopes + |> Scope.local word + in + { newVm | scopes = newScopes } + |> incrementProgramCounter + ) + |> Result.mapError (\_ -> WrongInput "local" (Type.toDebugString name)) + ) + + thing : Vm -> Result Error Vm thing vm = popValue1 vm @@ -1134,6 +1158,9 @@ execute instruction vm = Localmake -> localmake vm + Local -> + local vm + Thing -> thing vm diff --git a/tests/Test/Error.elm b/tests/Test/Error.elm index 64638a3..2895343 100644 --- a/tests/Test/Error.elm +++ b/tests/Test/Error.elm @@ -71,6 +71,7 @@ functionsWithInvalidArguments = , printsError "print fput \"wo \"rd" "fput doesn’t like wo as input" , printsError "make [] 1" "make doesn’t like [] as input" , printsError "localmake [] 1" "localmake doesn’t like [] as input" + , printsError "local []" "local doesn’t like [] as input" ] @@ -151,6 +152,11 @@ undefinedVariable = describe "prints error if undefined variable is used" <| [ printsError "print :variable" "variable has no value" , printsError ":variable" "variable has no value" + , printsError """to f +local "v make "v 1 print :v +end +f +print :v""" "v has no value" ] diff --git a/tests/Test/Run.elm b/tests/Test/Run.elm index cfd00a4..ab80b6d 100644 --- a/tests/Test/Run.elm +++ b/tests/Test/Run.elm @@ -278,6 +278,18 @@ foo""" ] +local : Test +local = + describe "variable defined by local is available in called function" <| + [ printsLines + """to f :recurse +ifelse :recurse [ local "v make "v "word f "false ] [ print :v ] +end +f "true""" + [ "word" ] + ] + + optionalArguments : Test optionalArguments = describe "define function with default value for optional parameter" <|