diff --git a/src/Compiler/AST/Canonical.elm b/src/Compiler/AST/Canonical.elm index 619696d41..7b3eeeb55 100644 --- a/src/Compiler/AST/Canonical.elm +++ b/src/Compiler/AST/Canonical.elm @@ -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) @@ -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 ) @@ -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)) diff --git a/src/Compiler/AST/Source.elm b/src/Compiler/AST/Source.elm index 90fb6f1dc..496dd7434 100644 --- a/src/Compiler/AST/Source.elm +++ b/src/Compiler/AST/Source.elm @@ -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) @@ -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 ) ] @@ -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 @@ -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 diff --git a/src/Compiler/Canonicalize/Expression.elm b/src/Compiler/Canonicalize/Expression.elm index 422f45d16..bc5c0586f 100644 --- a/src/Compiler/Canonicalize/Expression.elm +++ b/src/Compiler/Canonicalize/Expression.elm @@ -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 -> diff --git a/src/Compiler/Nitpick/PatternMatches.elm b/src/Compiler/Nitpick/PatternMatches.elm index a17fd4dc0..77c08b31c 100644 --- a/src/Compiler/Nitpick/PatternMatches.elm +++ b/src/Compiler/Nitpick/PatternMatches.elm @@ -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 -> diff --git a/src/Compiler/Optimize/Expression.elm b/src/Compiler/Optimize/Expression.elm index 89cf1231c..43f3f3226 100644 --- a/src/Compiler/Optimize/Expression.elm +++ b/src/Compiler/Optimize/Expression.elm @@ -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 -> diff --git a/src/Compiler/Parse/Expression.elm b/src/Compiler/Parse/Expression.elm index 6e16b712e..b2552ee92 100644 --- a/src/Compiler/Parse/Expression.elm +++ b/src/Compiler/Parse/Expression.elm @@ -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 @@ -272,28 +272,28 @@ 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)) ) ) ] @@ -301,6 +301,72 @@ record syntaxVersion start = ) +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 ) diff --git a/src/Compiler/Parse/Primitives.elm b/src/Compiler/Parse/Primitives.elm index 1a65b4fb4..ec5253a57 100644 --- a/src/Compiler/Parse/Primitives.elm +++ b/src/Compiler/Parse/Primitives.elm @@ -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 diff --git a/src/Compiler/Parse/Variable.elm b/src/Compiler/Parse/Variable.elm index 2a5b8464c..6116cd1b4 100644 --- a/src/Compiler/Parse/Variable.elm +++ b/src/Compiler/Parse/Variable.elm @@ -2,11 +2,13 @@ module Compiler.Parse.Variable exposing ( Upper(..) , chompInnerChars , chompLower + , chompUpper , foreignAlpha , foreignUpper , getInnerWidth , getInnerWidthHelp , getUpperWidth + , isDot , isReservedWord , lower , moduleName diff --git a/src/Compiler/Type/Constrain/Expression.elm b/src/Compiler/Type/Constrain/Expression.elm index 5b422f26e..63d3a4355 100644 --- a/src/Compiler/Type/Constrain/Expression.elm +++ b/src/Compiler/Type/Constrain/Expression.elm @@ -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 ->