Skip to content

Commit

Permalink
modify record referred by its qualified name (#78)
Browse files Browse the repository at this point in the history
Fixes #76
  • Loading branch information
decioferreira authored Feb 18, 2025
1 parent 0623e2b commit 1ba5d88
Show file tree
Hide file tree
Showing 9 changed files with 122 additions and 34 deletions.
8 changes: 5 additions & 3 deletions src/Compiler/AST/Canonical.elm
Original file line number Diff line number Diff line change
Expand Up @@ -109,7 +109,7 @@ type Expr_
| Case Expr (List CaseBranch)
| Accessor Name
| Access Expr (A.Located Name)
| Update Name Expr (Dict String (A.Located Name) FieldUpdate)
| Update (Maybe Name) Name Expr (Dict String (A.Located Name) FieldUpdate)
| Record (Dict String (A.Located Name) Expr)
| Unit
| Tuple Expr Expr (Maybe Expr)
Expand Down Expand Up @@ -779,9 +779,10 @@ expr_Encoder expr_ =
, ( "field", A.locatedEncoder Encode.string field )
]

Update name record updates ->
Update namespace name record updates ->
Encode.object
[ ( "type", Encode.string "Update" )
, ( "namespace", E.maybe Encode.string namespace )
, ( "name", Encode.string name )
, ( "record", exprEncoder record )
, ( "updates", E.assocListDict A.compareLocated (A.toValue >> Encode.string) fieldUpdateEncoder updates )
Expand Down Expand Up @@ -932,7 +933,8 @@ expr_Decoder =
(Decode.field "field" (A.locatedDecoder Decode.string))

"Update" ->
Decode.map3 Update
Decode.map4 Update
(Decode.field "namespace" (Decode.maybe Decode.string))
(Decode.field "name" Decode.string)
(Decode.field "record" exprDecoder)
(Decode.field "updates" (D.assocListDict A.toValue (A.locatedDecoder Decode.string) fieldUpdateDecoder))
Expand Down
15 changes: 12 additions & 3 deletions src/Compiler/AST/Source.elm
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,7 @@ type Expr_
| Case Expr (List ( Pattern, Expr ))
| Accessor Name
| Access Expr (A.Located Name)
| Update (A.Located Name) (List ( A.Located Name, Expr ))
| Update (A.Located ( Maybe Name, Name )) (List ( A.Located Name, Expr ))
| Record (List ( A.Located Name, Expr ))
| Unit
| Tuple Expr Expr (List Expr)
Expand Down Expand Up @@ -1033,7 +1033,7 @@ expr_Encoder expr_ =
Update name fields ->
Encode.object
[ ( "type", Encode.string "Update" )
, ( "name", A.locatedEncoder Encode.string name )
, ( "name", A.locatedEncoder (E.jsonPair (E.maybe Encode.string) Encode.string) name )
, ( "fields", Encode.list (E.jsonPair (A.locatedEncoder Encode.string) exprEncoder) fields )
]

Expand Down Expand Up @@ -1163,7 +1163,7 @@ expr_Decoder =

"Update" ->
Decode.map2 Update
(Decode.field "name" (A.locatedDecoder Decode.string))
(Decode.field "name" (A.locatedDecoder (jsonPair (Decode.maybe Decode.string) Decode.string)))
(Decode.field "fields"
(Decode.list
(Decode.map2 Tuple.pair
Expand Down Expand Up @@ -1203,6 +1203,15 @@ expr_Decoder =
)


{-| FIXME copied from Compiler.Json.Decode (cycle error)
-}
jsonPair : Decode.Decoder a -> Decode.Decoder b -> Decode.Decoder ( a, b )
jsonPair firstDecoder secondDecoder =
Decode.map2 Tuple.pair
(Decode.field "a" firstDecoder)
(Decode.field "b" secondDecoder)


varTypeEncoder : VarType -> Encode.Value
varTypeEncoder varType =
case varType of
Expand Down
15 changes: 12 additions & 3 deletions src/Compiler/Canonicalize/Expression.elm
Original file line number Diff line number Diff line change
Expand Up @@ -146,14 +146,23 @@ canonicalize env (A.At region expression) =
|> R.apply (canonicalize env record)
|> R.apply (R.ok field)

Src.Update (A.At reg name) fields ->
Src.Update (A.At reg ( maybeNamespace, name )) fields ->
let
expr : EResult FreeLocals w Can.Expr_
expr =
case maybeNamespace of
Nothing ->
findVar reg env name

Just namespace ->
findVarQual reg env namespace name

makeCanFields : R.RResult i w Error.Error (Dict String (A.Located Name) (R.RResult FreeLocals (List W.Warning) Error.Error Can.FieldUpdate))
makeCanFields =
Dups.checkLocatedFields_ (\r t -> R.fmap (Can.FieldUpdate r) (canonicalize env t)) fields
in
R.pure (Can.Update name)
|> R.apply (R.fmap (A.At reg) (findVar reg env name))
R.pure (Can.Update maybeNamespace name)
|> R.apply (R.fmap (A.At reg) expr)
|> R.apply (R.bind (Utils.sequenceADict A.toValue A.compareLocated) makeCanFields)

Src.Record fields ->
Expand Down
2 changes: 1 addition & 1 deletion src/Compiler/Nitpick/PatternMatches.elm
Original file line number Diff line number Diff line change
Expand Up @@ -340,7 +340,7 @@ checkExpr (A.At region expression) errors =
Can.Access record _ ->
checkExpr record errors

Can.Update _ record fields ->
Can.Update _ _ record fields ->
checkExpr record <| Dict.foldr A.compareLocated (\_ -> checkField) errors fields

Can.Record fields ->
Expand Down
2 changes: 1 addition & 1 deletion src/Compiler/Optimize/Expression.elm
Original file line number Diff line number Diff line change
Expand Up @@ -219,7 +219,7 @@ optimize cycle (A.At region expression) =
Names.registerField field (Opt.Access optRecord fieldPosition field)
)

Can.Update _ record updates ->
Can.Update _ _ record updates ->
Names.mapTraverse A.toValue A.compareLocated (optimizeUpdate cycle) updates
|> Names.bind
(\optUpdates ->
Expand Down
104 changes: 85 additions & 19 deletions src/Compiler/Parse/Expression.elm
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
module Compiler.Parse.Expression exposing (expression)

import Compiler.AST.Source as Src
import Compiler.Data.Name as Name
import Compiler.Data.Name as Name exposing (Name)
import Compiler.Parse.Keyword as Keyword
import Compiler.Parse.Number as Number
import Compiler.Parse.Pattern as Pattern
import Compiler.Parse.Primitives as P
import Compiler.Parse.Primitives as P exposing (Col, Row)
import Compiler.Parse.Shader as Shader
import Compiler.Parse.Space as Space
import Compiler.Parse.String as String
Expand Down Expand Up @@ -272,35 +272,101 @@ record syntaxVersion start =
P.oneOf E.RecordOpen
[ P.word1 '}' E.RecordOpen
|> P.bind (\_ -> P.addEnd start (Src.Record []))
, P.addLocation (foreignAlpha E.RecordField)
|> P.bind
(\starter ->
Space.chompAndCheckIndent E.RecordSpace E.RecordIndentEquals
|> P.bind (\_ -> P.word1 '|' E.RecordEquals)
|> P.bind (\_ -> Space.chompAndCheckIndent E.RecordSpace E.RecordIndentField)
|> P.bind (\_ -> chompField syntaxVersion)
|> P.bind (\firstField -> chompFields syntaxVersion [ firstField ])
|> P.bind (\fields -> P.addEnd start (Src.Update starter fields))
)
, P.addLocation (Var.lower E.RecordField)
|> P.bind
(\starter ->
Space.chompAndCheckIndent E.RecordSpace E.RecordIndentEquals
|> P.bind (\_ -> P.word1 '=' E.RecordEquals)
|> P.bind (\_ -> Space.chompAndCheckIndent E.RecordSpace E.RecordIndentExpr)
|> P.bind (\_ -> P.specialize E.RecordExpr (expression syntaxVersion))
|> P.bind
(\_ ->
P.oneOf E.RecordEquals
[ P.word1 '|' E.RecordEquals
|> P.bind (\_ -> Space.chompAndCheckIndent E.RecordSpace E.RecordIndentField)
|> P.bind (\_ -> chompField syntaxVersion)
|> P.bind (\firstField -> chompFields syntaxVersion [ firstField ])
|> P.bind (\fields -> P.addEnd start (Src.Update starter fields))
, P.word1 '=' E.RecordEquals
|> P.bind (\_ -> Space.chompAndCheckIndent E.RecordSpace E.RecordIndentExpr)
|> P.bind (\_ -> P.specialize E.RecordExpr (expression syntaxVersion))
|> P.bind
(\( value, end ) ->
Space.checkIndent end E.RecordIndentEnd
|> P.bind (\_ -> chompFields syntaxVersion [ ( starter, value ) ])
|> P.bind (\fields -> P.addEnd start (Src.Record fields))
)
]
(\( value, end ) ->
Space.checkIndent end E.RecordIndentEnd
|> P.bind (\_ -> chompFields syntaxVersion [ ( starter, value ) ])
|> P.bind (\fields -> P.addEnd start (Src.Record fields))
)
)
]
)
)


foreignAlpha : (Row -> Col -> x) -> P.Parser x ( Maybe Name, Name )
foreignAlpha toError =
P.Parser <|
\(P.State src pos end indent row col) ->
let
( ( alphaStart, alphaEnd ), ( newCol, varType ) ) =
foreignAlphaHelp src pos end col
in
if alphaStart == alphaEnd then
P.Eerr row newCol toError

else
case varType of
Src.LowVar ->
let
name : Name
name =
Name.fromPtr src alphaStart alphaEnd

newState : P.State
newState =
P.State src alphaEnd end indent row newCol
in
if alphaStart == pos then
if Var.isReservedWord name then
P.Eerr row col toError

else
P.Cok ( Nothing, name ) newState

else
let
home : Name
home =
Name.fromPtr src pos (alphaStart + -1)
in
P.Cok ( Just home, name ) newState

Src.CapVar ->
P.Eerr row col toError


foreignAlphaHelp : String -> Int -> Int -> Col -> ( ( Int, Int ), ( Col, Src.VarType ) )
foreignAlphaHelp src pos end col =
let
( lowerPos, lowerCol ) =
Var.chompLower src pos end col
in
if pos < lowerPos then
( ( pos, lowerPos ), ( lowerCol, Src.LowVar ) )

else
let
( upperPos, upperCol ) =
Var.chompUpper src pos end col
in
if pos == upperPos then
( ( pos, pos ), ( col, Src.CapVar ) )

else if Var.isDot src upperPos end then
foreignAlphaHelp src (upperPos + 1) end (upperCol + 1)

else
( ( pos, upperPos ), ( upperCol, Src.CapVar ) )


type alias Field =
( A.Located Name.Name, Src.Expr )

Expand Down
6 changes: 3 additions & 3 deletions src/Compiler/Parse/Primitives.elm
Original file line number Diff line number Diff line change
Expand Up @@ -160,11 +160,11 @@ bind callback (Parser parserA) =
case callback a of
Parser parserB ->
case parserB s of
Eok a_ s_ ->
Cok a_ s_ ->
Cok a_ s_

Eerr r c t ->
Cerr r c t
Eok a_ s_ ->
Cok a_ s_

result ->
result
Expand Down
2 changes: 2 additions & 0 deletions src/Compiler/Parse/Variable.elm
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,13 @@ module Compiler.Parse.Variable exposing
( Upper(..)
, chompInnerChars
, chompLower
, chompUpper
, foreignAlpha
, foreignUpper
, getInnerWidth
, getInnerWidthHelp
, getUpperWidth
, isDot
, isReservedWord
, lower
, moduleName
Expand Down
2 changes: 1 addition & 1 deletion src/Compiler/Type/Constrain/Expression.elm
Original file line number Diff line number Diff line change
Expand Up @@ -182,7 +182,7 @@ constrain rtv (A.At region expression) expected =
)
)

Can.Update name expr fields ->
Can.Update _ name expr fields ->
constrainUpdate rtv region name expr fields expected

Can.Record fields ->
Expand Down

0 comments on commit 1ba5d88

Please sign in to comment.