Compare commits
4 Commits
f3d37076ee
...
master
| Author | SHA1 | Date | |
|---|---|---|---|
| 1a55882e80 | |||
| 025b21c954 | |||
| d4303606df | |||
| d742cc9d88 |
@@ -9,18 +9,17 @@
|
|||||||
<div id="elm-container">
|
<div id="elm-container">
|
||||||
</div>
|
</div>
|
||||||
<script>
|
<script>
|
||||||
var program = `
|
var program = `move(0, 0);
|
||||||
move(0, 0);
|
|
||||||
define line(x1, y1, x2, y2) {
|
define line(x1, y1, x2, y2) {
|
||||||
pen up;
|
pen up;
|
||||||
move(x1, y1);
|
move(x1, y1);
|
||||||
pen down;
|
pen down;
|
||||||
move(x2, y2);
|
move(x2, y2);
|
||||||
};
|
}
|
||||||
define nix(x, y, width, height) {
|
define nix(x, y, width, height) {
|
||||||
call line (x, y, x + width, y + height);
|
call line (x, y, x + width, y + height);
|
||||||
call line (x + width, y, x, y + height);
|
call line (x + width, y, x, y + height);
|
||||||
};
|
}
|
||||||
call nix(0, 0, 20, 20);
|
call nix(0, 0, 20, 20);
|
||||||
`
|
`
|
||||||
var container = document.getElementById("elm-container");
|
var container = document.getElementById("elm-container");
|
||||||
|
|||||||
120
src/Main.elm
120
src/Main.elm
@@ -4,7 +4,7 @@ import Html.Events exposing (onInput)
|
|||||||
import Browser exposing (element)
|
import Browser exposing (element)
|
||||||
import Canvas exposing (Shape)
|
import Canvas exposing (Shape)
|
||||||
import Dict exposing (Dict)
|
import Dict exposing (Dict)
|
||||||
import Parser exposing (Parser, Problem(..), DeadEnd, (|.), (|=), variable, succeed, symbol, int, spaces, map, oneOf, lazy, sequence, Trailing(..), keyword, run, backtrackable)
|
import Parser exposing (Parser, Problem(..), DeadEnd, (|.), (|=), variable, succeed, symbol, int, spaces, map, oneOf, lazy, sequence, Trailing(..), keyword, run, backtrackable, end)
|
||||||
import Color
|
import Color
|
||||||
import Canvas exposing (Point, path, lineTo, circle, shapes, stroke, lineWidth, fill, rect)
|
import Canvas exposing (Point, path, lineTo, circle, shapes, stroke, lineWidth, fill, rect)
|
||||||
import Set
|
import Set
|
||||||
@@ -90,7 +90,7 @@ parseExpr = oneOf [ lazy (\_ -> backtrackable parseSum), parseTerm ]
|
|||||||
parseProg : Parser LogoProg
|
parseProg : Parser LogoProg
|
||||||
parseProg = sequence
|
parseProg = sequence
|
||||||
{ start = ""
|
{ start = ""
|
||||||
, separator = ";"
|
, separator = ""
|
||||||
, end = ""
|
, end = ""
|
||||||
, spaces = spaces
|
, spaces = spaces
|
||||||
, item = lazy (\_ -> parseCmd)
|
, item = lazy (\_ -> parseCmd)
|
||||||
@@ -135,6 +135,8 @@ parseCall = succeed Call
|
|||||||
, item = parseExpr
|
, item = parseExpr
|
||||||
, trailing = Forbidden
|
, trailing = Forbidden
|
||||||
}
|
}
|
||||||
|
|. spaces
|
||||||
|
|. symbol ";"
|
||||||
|
|
||||||
parsePenMode : Parser LogoPenMode
|
parsePenMode : Parser LogoPenMode
|
||||||
parsePenMode = oneOf
|
parsePenMode = oneOf
|
||||||
@@ -147,6 +149,8 @@ parsePen = succeed Pen
|
|||||||
|. keyword "pen"
|
|. keyword "pen"
|
||||||
|. spaces
|
|. spaces
|
||||||
|= parsePenMode
|
|= parsePenMode
|
||||||
|
|. spaces
|
||||||
|
|. symbol ";"
|
||||||
|
|
||||||
parseMove : Parser LogoCmd
|
parseMove : Parser LogoCmd
|
||||||
parseMove = succeed Move
|
parseMove = succeed Move
|
||||||
@@ -158,7 +162,10 @@ parseMove = succeed Move
|
|||||||
|. symbol ","
|
|. symbol ","
|
||||||
|. spaces
|
|. spaces
|
||||||
|= parseExpr
|
|= parseExpr
|
||||||
|
|. spaces
|
||||||
|. symbol ")"
|
|. symbol ")"
|
||||||
|
|. spaces
|
||||||
|
|. symbol ";"
|
||||||
|
|
||||||
{-
|
{-
|
||||||
======= Semantics Code =======
|
======= Semantics Code =======
|
||||||
@@ -199,9 +206,42 @@ initialState =
|
|||||||
, board = []
|
, board = []
|
||||||
}
|
}
|
||||||
|
|
||||||
|
updatePosition : Coord -> State -> State
|
||||||
|
updatePosition c state =
|
||||||
|
let
|
||||||
|
newBoard = case state.penMode of
|
||||||
|
Up -> state.board
|
||||||
|
Down -> (state.pos, c)::state.board
|
||||||
|
in
|
||||||
|
{ state | pos = c, board = newBoard }
|
||||||
|
|
||||||
|
registerFunction : String -> Function -> State -> State
|
||||||
|
registerFunction s f state = { state | scope = setScopeFunction s f state.scope }
|
||||||
|
|
||||||
|
registerVariable : String -> Int -> State -> State
|
||||||
|
registerVariable s v state = { state | scope = setScopeVariable s v state.scope }
|
||||||
|
|
||||||
|
setPenMode : LogoPenMode -> State -> State
|
||||||
|
setPenMode m state = { state | penMode = m}
|
||||||
|
|
||||||
|
upScope : State -> State
|
||||||
|
upScope state = { state | scope = Child state.scope Dict.empty Dict.empty }
|
||||||
|
|
||||||
|
downScope : State -> State
|
||||||
|
downScope state =
|
||||||
|
let
|
||||||
|
newScope = case state.scope of
|
||||||
|
End -> End
|
||||||
|
Child p _ _ -> p
|
||||||
|
in
|
||||||
|
{ state | scope = newScope }
|
||||||
|
|
||||||
unit : a -> Step a
|
unit : a -> Step a
|
||||||
unit a state = Ok (a, state)
|
unit a state = Ok (a, state)
|
||||||
|
|
||||||
|
err : String -> Step a
|
||||||
|
err s state = Err s
|
||||||
|
|
||||||
bind : Step a -> (a -> Step b) -> Step b
|
bind : Step a -> (a -> Step b) -> Step b
|
||||||
bind sa f state = case sa state of
|
bind sa f state = case sa state of
|
||||||
Ok (a, newState) -> f a newState
|
Ok (a, newState) -> f a newState
|
||||||
@@ -210,45 +250,24 @@ bind sa f state = case sa state of
|
|||||||
rbind : (a -> Step b) -> Step a -> Step b
|
rbind : (a -> Step b) -> Step a -> Step b
|
||||||
rbind f sa = bind sa f
|
rbind f sa = bind sa f
|
||||||
|
|
||||||
updatePosition : Coord -> Step ()
|
get : Step State
|
||||||
updatePosition c state =
|
get s = Ok (s, s)
|
||||||
let
|
|
||||||
newBoard = case state.penMode of
|
|
||||||
Up -> state.board
|
|
||||||
Down -> (state.pos, c)::state.board
|
|
||||||
in
|
|
||||||
Ok ((), { state | pos = c, board = newBoard })
|
|
||||||
|
|
||||||
registerFunction : String -> Function -> Step ()
|
put : State -> Step ()
|
||||||
registerFunction s f state = Ok ((), { state | scope = setScopeFunction s f state.scope })
|
put s _ = Ok ((), s)
|
||||||
|
|
||||||
registerVariable : String -> Int -> Step ()
|
modify : (State -> State) -> Step ()
|
||||||
registerVariable s v state = Ok ((), { state | scope = setScopeVariable s v state.scope })
|
modify f = get |> rbind (put << f)
|
||||||
|
|
||||||
setPenMode : LogoPenMode -> Step ()
|
|
||||||
setPenMode m state = Ok ((), { state | penMode = m})
|
|
||||||
|
|
||||||
upScope : Step ()
|
|
||||||
upScope state = Ok ((), { state | scope = Child state.scope Dict.empty Dict.empty })
|
|
||||||
|
|
||||||
downScope : Step ()
|
|
||||||
downScope state =
|
|
||||||
let
|
|
||||||
newScope = case state.scope of
|
|
||||||
End -> End
|
|
||||||
Child p _ _ -> p
|
|
||||||
in
|
|
||||||
Ok ((), { state | scope = newScope })
|
|
||||||
|
|
||||||
lookupFunction : String -> Step Function
|
lookupFunction : String -> Step Function
|
||||||
lookupFunction s state = case scopeFunction s state.scope of
|
lookupFunction s = get |> rbind (\st -> case scopeFunction s st.scope of
|
||||||
Just f -> Ok (f, state)
|
Just f -> unit f
|
||||||
Nothing -> Err ("No function with name " ++ s)
|
Nothing -> err ("No function with name " ++ s))
|
||||||
|
|
||||||
lookupVariable : String -> Step Int
|
lookupVariable : String -> Step Int
|
||||||
lookupVariable s state = case scopeVariable s state.scope of
|
lookupVariable s = get |> rbind (\st -> case scopeVariable s st.scope of
|
||||||
Just i -> Ok (i, state)
|
Just v -> unit v
|
||||||
Nothing -> Err ("No variable with name " ++ s)
|
Nothing -> err ("No variable with name " ++ s))
|
||||||
|
|
||||||
evaluateExp : LogoExpr -> Step Int
|
evaluateExp : LogoExpr -> Step Int
|
||||||
evaluateExp le = case le of
|
evaluateExp le = case le of
|
||||||
@@ -260,24 +279,27 @@ evaluateAllExps : List LogoExpr -> Step (List Int)
|
|||||||
evaluateAllExps = List.foldr (\x acc -> acc |> rbind (\vs -> evaluateExp x |> rbind (\v -> unit (v::vs)))) (unit [])
|
evaluateAllExps = List.foldr (\x acc -> acc |> rbind (\vs -> evaluateExp x |> rbind (\v -> unit (v::vs)))) (unit [])
|
||||||
|
|
||||||
registerAllVariables : List (String, Int) -> Step ()
|
registerAllVariables : List (String, Int) -> Step ()
|
||||||
registerAllVariables = List.foldl (\(s, i) m -> bind m (\_ -> registerVariable s i)) (unit ())
|
registerAllVariables = List.foldl (\(s, i) m -> bind m (\_ -> modify <| registerVariable s i)) (unit ())
|
||||||
|
|
||||||
zip : List a -> List b -> List (a, b)
|
zipParams : List String -> List Int -> Step (List (String, Int))
|
||||||
zip la lb = case (la, lb) of
|
zipParams la lb = case (la, lb) of
|
||||||
(a::lat, b::lbt) -> (a, b)::zip lat lbt
|
(a::lat, b::lbt) -> zipParams lat lbt |> rbind (\ps -> unit <| (a, b)::ps)
|
||||||
_ -> []
|
([], []) -> unit []
|
||||||
|
([], _) -> err "Passing too many parameters to macro call"
|
||||||
|
(_, []) -> err "Not enough parameters in macro call"
|
||||||
|
|
||||||
evaluateCmd : LogoCmd -> Step ()
|
evaluateCmd : LogoCmd -> Step ()
|
||||||
evaluateCmd c = case c of
|
evaluateCmd c = case c of
|
||||||
Move l r -> evaluateExp l |> rbind (\x -> evaluateExp r |> rbind (\y -> updatePosition (x, y)))
|
Move l r -> evaluateExp l |> rbind (\x -> evaluateExp r |> rbind (\y -> modify <| updatePosition (x, y)))
|
||||||
Define n xs prg -> registerFunction n (xs, prg)
|
Define n xs prg -> modify <| registerFunction n (xs, prg)
|
||||||
Pen mode -> setPenMode mode
|
Pen mode -> modify <| setPenMode mode
|
||||||
Call n args -> lookupFunction n
|
Call n args -> lookupFunction n
|
||||||
|> rbind (\(ns, prg) -> evaluateAllExps args
|
|> rbind (\(ns, prg) -> evaluateAllExps args
|
||||||
|> rbind (\vs -> upScope
|
|> rbind (\vs -> modify upScope
|
||||||
|> rbind (\_ -> registerAllVariables (zip ns vs)
|
|> rbind (\_ -> zipParams ns vs
|
||||||
|> rbind (\_ -> evaluateAll prg
|
|> rbind (\ps -> registerAllVariables ps
|
||||||
|> rbind (\_ -> downScope)))))
|
|> rbind (\_ -> evaluateAll prg
|
||||||
|
|> rbind (\_ -> modify downScope))))))
|
||||||
|
|
||||||
evaluateAll : LogoProg -> Step ()
|
evaluateAll : LogoProg -> Step ()
|
||||||
evaluateAll prg = List.foldl rbind (unit ()) <| List.map (\c _ -> evaluateCmd c) prg
|
evaluateAll prg = List.foldl rbind (unit ()) <| List.map (\c _ -> evaluateCmd c) prg
|
||||||
@@ -350,9 +372,9 @@ init fs =
|
|||||||
view : Model -> Html Msg
|
view : Model -> Html Msg
|
||||||
view m =
|
view m =
|
||||||
let
|
let
|
||||||
|
parseResult = Result.mapError humanParseError (run (parseProg |. end) m.programText)
|
||||||
evalResult = Result.map (\(_, s) -> s)
|
evalResult = Result.map (\(_, s) -> s)
|
||||||
<| Result.andThen (\prg -> evaluateAll prg initialState)
|
<| Result.andThen (\prg -> evaluateAll prg initialState) parseResult
|
||||||
<| Result.mapError humanParseError (run parseProg m.programText)
|
|
||||||
toRender = Result.withDefault initialState evalResult
|
toRender = Result.withDefault initialState evalResult
|
||||||
error = case evalResult of
|
error = case evalResult of
|
||||||
Err e -> [ p [ classList [ ("centered", True), ("error", True), ("shadow", True) ] ] [ text e ] ]
|
Err e -> [ p [ classList [ ("centered", True), ("error", True), ("shadow", True) ] ] [ text e ] ]
|
||||||
|
|||||||
Reference in New Issue
Block a user