roc/examples/false-interpreter/Context.roc

108 lines
4.0 KiB
Plaintext
Raw Normal View History

2021-09-30 02:01:54 +03:00
interface Context
exposes [Context, Data, with, getChar, Option, pushStack, popStack, toStr, inWhileScope]
imports [pf.File, pf.Task.{ Task }, Variable.{ Variable }]
2021-09-30 02:01:54 +03:00
Option a : [Some a, None]
2021-09-30 02:01:54 +03:00
# The underlying context of the current location within the file
Data : [Lambda (List U8), Number I32, Var Variable]
# While loops are special and have their own Scope specific state.
WhileState : { cond : List U8, body : List U8, state : [InCond, InBody] }
2021-12-22 04:24:44 +03:00
Scope : { data : Option File.Handle, index : Nat, buf : List U8, whileInfo : Option WhileState }
State : [Executing, InComment, InLambda Nat (List U8), InString (List U8), InNumber I32, InSpecialChar, LoadChar]
2021-12-22 04:24:44 +03:00
Context : { scopes : List Scope, stack : List Data, vars : List Data, state : State }
2021-09-30 02:01:54 +03:00
2021-12-22 04:17:31 +03:00
pushStack : Context, Data -> Context
2021-09-30 02:01:54 +03:00
pushStack = \ctx, data ->
2021-12-22 04:17:31 +03:00
{ ctx & stack: List.append ctx.stack data }
2021-09-30 02:01:54 +03:00
2021-10-02 20:40:16 +03:00
# I think an open tag union should just work here.
# Instead at a call sites, I need to match on the error and then return the same error.
# Otherwise it hits unreachable code in ir.rs
popStack : Context -> Result [T Context Data] [EmptyStack]*
2021-09-30 02:01:54 +03:00
popStack = \ctx ->
when List.last ctx.stack is
Ok val ->
2021-10-06 00:15:53 +03:00
poppedCtx = { ctx & stack: List.dropAt ctx.stack (List.len ctx.stack - 1) }
2021-12-22 04:17:31 +03:00
2021-09-30 02:01:54 +03:00
Ok (T poppedCtx val)
2022-07-07 00:35:56 +03:00
2021-09-30 02:01:54 +03:00
Err ListWasEmpty ->
Err EmptyStack
2021-12-22 04:17:31 +03:00
toStrData : Data -> Str
2021-09-30 02:01:54 +03:00
toStrData = \data ->
when data is
2022-07-07 00:35:56 +03:00
Lambda _ -> "[]"
Number n -> Num.toStr (Num.intCast n)
Var v -> Variable.toStr v
2021-09-30 02:01:54 +03:00
2021-12-22 04:17:31 +03:00
toStrState : State -> Str
toStrState = \state ->
when state is
2022-07-07 00:35:56 +03:00
Executing -> "Executing"
InComment -> "InComment"
InString _ -> "InString"
InNumber _ -> "InNumber"
InLambda _ _ -> "InLambda"
InSpecialChar -> "InSpecialChar"
LoadChar -> "LoadChar"
2021-12-22 04:17:31 +03:00
toStr : Context -> Str
toStr = \{ scopes, stack, state, vars } ->
depth = Num.toStr (List.len scopes)
stateStr = toStrState state
2021-09-30 02:01:54 +03:00
stackStr = Str.joinWith (List.map stack toStrData) " "
varsStr = Str.joinWith (List.map vars toStrData) " "
2021-12-22 04:17:31 +03:00
"\n============\nDepth: \(depth)\nState: \(stateStr)\nStack: [\(stackStr)]\nVars: [\(varsStr)]\n============\n"
2021-09-30 02:01:54 +03:00
2021-10-02 20:40:16 +03:00
with : Str, (Context -> Task {} a) -> Task {} a
2021-09-30 02:01:54 +03:00
with = \path, callback ->
2021-10-02 20:40:16 +03:00
handle <- File.withOpen path
# I cant define scope here and put it in the list in callback. It breaks alias anaysis.
# Instead I have to inline this.
# root_scope = { data: Some handle, index: 0, buf: [], whileInfo: None }
callback { scopes: [{ data: Some handle, index: 0, buf: [], whileInfo: None }], state: Executing, stack: [], vars: List.repeat (Number 0) Variable.totalCount }
2021-09-30 02:01:54 +03:00
# I am pretty sure there is a syntax to destructure and keep a reference to the whole, but Im not sure what it is.
getChar : Context -> Task [T U8 Context] [EndOfData, NoScope]*
2021-09-30 02:01:54 +03:00
getChar = \ctx ->
when List.last ctx.scopes is
Ok scope ->
(T val newScope) <- Task.await (getCharScope scope)
2021-12-22 04:17:31 +03:00
Task.succeed (T val { ctx & scopes: List.set ctx.scopes (List.len ctx.scopes - 1) newScope })
2022-07-07 00:35:56 +03:00
Err ListWasEmpty ->
Task.fail NoScope
getCharScope : Scope -> Task [T U8 Scope] [EndOfData, NoScope]*
getCharScope = \scope ->
when List.get scope.buf scope.index is
2021-12-22 04:17:31 +03:00
Ok val ->
Task.succeed (T val { scope & index: scope.index + 1 })
2022-07-07 00:35:56 +03:00
2021-12-22 04:17:31 +03:00
Err OutOfBounds ->
when scope.data is
2021-09-30 02:01:54 +03:00
Some h ->
bytes <- Task.await (File.chunk h)
2021-09-30 02:01:54 +03:00
when List.first bytes is
Ok val ->
2021-11-06 17:29:08 +03:00
# This starts at 1 because the first character is already being returned.
2021-12-22 04:17:31 +03:00
Task.succeed (T val { scope & buf: bytes, index: 1 })
2022-07-07 00:35:56 +03:00
2021-12-22 04:17:31 +03:00
Err ListWasEmpty ->
2021-09-30 02:01:54 +03:00
Task.fail EndOfData
2022-07-07 00:35:56 +03:00
2021-09-30 02:01:54 +03:00
None ->
Task.fail EndOfData
2021-12-22 04:17:31 +03:00
inWhileScope : Context -> Bool
inWhileScope = \ctx ->
when List.last ctx.scopes is
Ok scope ->
scope.whileInfo != None
2022-07-07 00:35:56 +03:00
Err ListWasEmpty ->
2022-03-06 01:32:34 +03:00
False