diff --git a/src/Elm/AST/Canonical.elm b/src/Elm/AST/Canonical.elm index d8577dfd..e546a279 100644 --- a/src/Elm/AST/Canonical.elm +++ b/src/Elm/AST/Canonical.elm @@ -85,6 +85,7 @@ type Expr | Tuple3 LocatedExpr LocatedExpr LocatedExpr | Record (Dict VarName (Binding LocatedExpr)) | Case LocatedExpr (List { pattern : LocatedPattern, body : LocatedExpr }) + | Shader String type alias LocatedPattern = @@ -212,6 +213,9 @@ unwrap expr = ) branches + Shader shader -> + Unwrapped.Shader shader + {-| Discard the [location metadata](Elm.Data.Located#Located). -} @@ -371,6 +375,9 @@ fromUnwrapped expr = ) branches + Unwrapped.Shader shader -> + Shader shader + {-| Adds [**dummy** locations](Elm.Data.Located#dummyRegion) to the [Unwrapped.Pattern](Elm.AST.Canonical.Unwrapped#Pattern). -} diff --git a/src/Elm/AST/Canonical/Unwrapped.elm b/src/Elm/AST/Canonical/Unwrapped.elm index 9bc884e9..936b0afd 100644 --- a/src/Elm/AST/Canonical/Unwrapped.elm +++ b/src/Elm/AST/Canonical/Unwrapped.elm @@ -42,6 +42,7 @@ type Expr | Tuple3 Expr Expr Expr | Record (Dict VarName (Binding Expr)) | Case Expr (List { pattern : Pattern, body : Expr }) + | Shader String type Pattern diff --git a/src/Elm/AST/Frontend.elm b/src/Elm/AST/Frontend.elm index f433361d..28e24107 100644 --- a/src/Elm/AST/Frontend.elm +++ b/src/Elm/AST/Frontend.elm @@ -15,6 +15,7 @@ still there. import Dict exposing (Dict) import Elm.AST.Frontend.Unwrapped as Unwrapped +import Elm.AST.Shader as Shader import Elm.Data.Binding as Binding exposing (Binding) import Elm.Data.Located as Located exposing (Located) import Elm.Data.Module exposing (Module) @@ -73,6 +74,12 @@ type Expr | Tuple3 LocatedExpr LocatedExpr LocatedExpr | Record (List (Binding LocatedExpr)) | Case LocatedExpr (List { pattern : LocatedPattern, body : LocatedExpr }) + | Shader + String + { attribute : Dict VarName Shader.Type + , uniform : Dict VarName Shader.Type + , varying : Dict VarName Shader.Type + } type alias LocatedPattern = @@ -191,6 +198,9 @@ recurse f expr = ) branches + Shader _ _ -> + expr + {-| [Transform](/packages/Janiczek/transform/latest/Transform#transformAll) the expression using the provided function. @@ -311,6 +321,9 @@ unwrap expr = ) branches + Shader value types -> + Unwrapped.Shader value types + {-| Discard the [location metadata](Elm.Data.Located#Located). -} diff --git a/src/Elm/AST/Frontend/Unwrapped.elm b/src/Elm/AST/Frontend/Unwrapped.elm index 69e59632..06383088 100644 --- a/src/Elm/AST/Frontend/Unwrapped.elm +++ b/src/Elm/AST/Frontend/Unwrapped.elm @@ -13,6 +13,8 @@ Convert to it using the [`Elm.AST.Frontend.unwrap`](Elm.AST.Frontend#unwrap). -} +import Dict exposing (Dict) +import Elm.AST.Shader as Shader import Elm.Data.Binding exposing (Binding) import Elm.Data.Qualifiedness exposing (PossiblyQualified) import Elm.Data.VarName exposing (VarName) @@ -41,6 +43,12 @@ type Expr | Tuple3 Expr Expr Expr | Record (List (Binding Expr)) | Case Expr (List { pattern : Pattern, body : Expr }) + | Shader + String + { attribute : Dict VarName Shader.Type + , uniform : Dict VarName Shader.Type + , varying : Dict VarName Shader.Type + } type Pattern diff --git a/src/Elm/AST/Shader.elm b/src/Elm/AST/Shader.elm new file mode 100644 index 00000000..a97df9f5 --- /dev/null +++ b/src/Elm/AST/Shader.elm @@ -0,0 +1,11 @@ +module Elm.AST.Shader exposing (Type(..)) + + +type Type + = Int + | Float + | V2 + | V3 + | V4 + | M4 + | Texture diff --git a/src/Elm/AST/Typed.elm b/src/Elm/AST/Typed.elm index 9722b619..72b8fe85 100644 --- a/src/Elm/AST/Typed.elm +++ b/src/Elm/AST/Typed.elm @@ -84,6 +84,7 @@ type Expr_ | Tuple3 LocatedExpr LocatedExpr LocatedExpr | Record (Dict VarName (Binding LocatedExpr)) | Case LocatedExpr (List { pattern : LocatedPattern, body : LocatedExpr }) + | Shader String type alias LocatedPattern = @@ -214,6 +215,9 @@ recurse fn locatedExpr = } ) branches + + Shader _ -> + expr ) @@ -308,6 +312,9 @@ recursiveChildren fn locatedExpr = Case e branches -> fn e ++ List.fastConcatMap (.body >> fn) branches + Shader _ -> + [] + mapExpr : (Expr_ -> Expr_) -> LocatedExpr -> LocatedExpr mapExpr fn locatedExpr = @@ -451,6 +458,9 @@ unwrap expr = } ) branches + + Shader shader -> + Unwrapped.Shader shader , type_ ) @@ -610,6 +620,9 @@ dropTypes locatedExpr = } ) branches + + Shader shader -> + Canonical.Shader shader ) diff --git a/src/Elm/AST/Typed/Unwrapped.elm b/src/Elm/AST/Typed/Unwrapped.elm index 651be0fe..77e73f59 100644 --- a/src/Elm/AST/Typed/Unwrapped.elm +++ b/src/Elm/AST/Typed/Unwrapped.elm @@ -49,6 +49,7 @@ type Expr_ | Tuple3 Expr Expr Expr | Record (Dict VarName (Binding Expr)) | Case Expr (List { pattern : Pattern, body : Expr }) + | Shader String type alias Pattern = diff --git a/src/Elm/Compiler/Error.elm b/src/Elm/Compiler/Error.elm index b6a6c12b..99af7c87 100644 --- a/src/Elm/Compiler/Error.elm +++ b/src/Elm/Compiler/Error.elm @@ -181,6 +181,7 @@ type ParseProblem | ExpectingScientificNotationPlus | ExpectingScientificNotationMinus | IntZeroCannotHaveScientificNotation + | ShaderProblem type ParseCompilerBug @@ -640,6 +641,9 @@ parseProblemToString problem = IntZeroCannotHaveScientificNotation -> "IntZeroCannotHaveScientificNotation" + ShaderProblem -> + "ShaderProblem" + parseCompilerBugToString : ParseCompilerBug -> String parseCompilerBugToString bug = diff --git a/src/Elm/Data/Type.elm b/src/Elm/Data/Type.elm index 34a0c8cb..d0e1bffb 100644 --- a/src/Elm/Data/Type.elm +++ b/src/Elm/Data/Type.elm @@ -19,6 +19,7 @@ The main confusion point here is "what is the -} import Dict exposing (Dict) +import Elm.AST.Shader as Shader import Elm.Data.VarName exposing (VarName) import OurExtras.Dict as Dict import OurExtras.List as List @@ -129,6 +130,11 @@ type Type a , name : String , args : List (TypeOrId a) } + | Shader + { attribute : Dict VarName Shader.Type + , uniform : Dict VarName Shader.Type + , varying : Dict VarName Shader.Type + } {-| Unwrap the string inside the type variable @@ -228,6 +234,9 @@ isParametric typeOrId = UserDefinedType { args } -> List.any f args + Shader _ -> + False + varNames : Type a -> List String varNames type_ = @@ -297,6 +306,9 @@ recursiveChildren fn type_ = UserDefinedType { args } -> List.fastConcatMap fn_ args + Shader _ -> + [] + {-| Find all the children of this expression (and their children, etc...) -} @@ -345,6 +357,9 @@ recursiveChildren_ fn typeOrId = Type (UserDefinedType { args }) -> List.fastConcatMap fn args + Type (Shader _) -> + [] + mapTypeOrId : (a -> b) -> TypeOrId a -> TypeOrId b mapTypeOrId fn typeOrId = @@ -414,6 +429,9 @@ mapType fn type_ = , args = List.map f r.args } + Shader shaderInfo -> + Shader shaderInfo + combineType : Type (Result err a) -> Result err (Type a) combineType type_ = @@ -490,6 +508,9 @@ combineType type_ = |> Result.Extra.combine ) + Shader shaderInfo -> + Ok (Shader shaderInfo) + combineTypeOrId : TypeOrId (Result err a) -> Result err (TypeOrId a) combineTypeOrId typeOrId = diff --git a/src/Elm/Data/Type/ToString.elm b/src/Elm/Data/Type/ToString.elm index 4a7583d8..e941c477 100644 --- a/src/Elm/Data/Type/ToString.elm +++ b/src/Elm/Data/Type/ToString.elm @@ -331,6 +331,9 @@ toStringType_ qualifiednessToString state type_ = else ( "{ " ++ bindingsStr ++ " }", state1 ) + Shader _ -> + ( "Shader", state ) + getName : State -> Int -> ( String, State ) getName ((State { counter, mapping, used }) as state) varId = @@ -497,3 +500,6 @@ shouldWrapParens typeOrId = Record _ -> False + + Shader _ -> + False diff --git a/src/Stage/Desugar.elm b/src/Stage/Desugar.elm index 50da640a..27590026 100644 --- a/src/Stage/Desugar.elm +++ b/src/Stage/Desugar.elm @@ -248,6 +248,9 @@ desugarExpr modules thisModule locatedExpr = |> Result.combine ) + Frontend.Shader shader _ -> + return <| Canonical.Shader shader + desugarPattern : Frontend.LocatedPattern diff --git a/src/Stage/Emit.elm b/src/Stage/Emit.elm index 1b4d727d..73d85fd8 100644 --- a/src/Stage/Emit.elm +++ b/src/Stage/Emit.elm @@ -564,3 +564,6 @@ findDependenciesOfExpr modules locatedExpr = Result.map2 (++) (f e) branchesDependencies + + Shader _ -> + Ok [] diff --git a/src/Stage/Emit/JavaScript.elm b/src/Stage/Emit/JavaScript.elm index 92ed2b4e..46b91893 100644 --- a/src/Stage/Emit/JavaScript.elm +++ b/src/Stage/Emit/JavaScript.elm @@ -132,6 +132,9 @@ emitExpr located = Case _ _ -> "TODO" + Shader _ -> + "TODO" + emitDeclaration : Declaration Typed.LocatedExpr Never Qualified -> String emitDeclaration { module_, name, body } = diff --git a/src/Stage/Emit/JsonAST.elm b/src/Stage/Emit/JsonAST.elm index d0e68683..a615fbb3 100644 --- a/src/Stage/Emit/JsonAST.elm +++ b/src/Stage/Emit/JsonAST.elm @@ -155,6 +155,9 @@ emitExpr located = ) ] + Shader shader -> + encode "shader" [ ( "value", Encode.string shader ) ] + emitDeclaration : Declaration Typed.LocatedExpr Never Qualified -> Value emitDeclaration { module_, name, body } = diff --git a/src/Stage/InferTypes.elm b/src/Stage/InferTypes.elm index c8440a64..66cac651 100644 --- a/src/Stage/InferTypes.elm +++ b/src/Stage/InferTypes.elm @@ -212,6 +212,9 @@ getBetterType substitutionMap typeOrId = Record <| Dict.map (\_ binding -> getBetterType substitutionMap binding) bindings + Shader _ -> + typeOrId + unifyWithTypeAnnotation : Dict ( ModuleName, VarName ) (ConcreteType Qualified) diff --git a/src/Stage/InferTypes/AssignIds.elm b/src/Stage/InferTypes/AssignIds.elm index 8d50508f..22084aa6 100644 --- a/src/Stage/InferTypes/AssignIds.elm +++ b/src/Stage/InferTypes/AssignIds.elm @@ -304,6 +304,9 @@ assignIdsHelp currentId located = assignId newId <| Typed.Case e_ branches_ + Canonical.Shader shader -> + assignId currentId (Typed.Shader shader) + assignPatternIds : Int -> Canonical.LocatedPattern -> ( Typed.LocatedPattern, Int ) assignPatternIds currentId locatedCanonicalPattern = diff --git a/src/Stage/InferTypes/GenerateEquations.elm b/src/Stage/InferTypes/GenerateEquations.elm index 42c53e41..6785bdc5 100644 --- a/src/Stage/InferTypes/GenerateEquations.elm +++ b/src/Stage/InferTypes/GenerateEquations.elm @@ -428,6 +428,9 @@ generateEquations currentId located = , newId ) + Typed.Shader _ -> + Debug.todo "Shader" + findArgumentUsages : VarName -> Typed.LocatedExpr -> List Typed.LocatedExpr findArgumentUsages argument bodyExpr = diff --git a/src/Stage/InferTypes/Unify.elm b/src/Stage/InferTypes/Unify.elm index 4495b4dc..0f442391 100644 --- a/src/Stage/InferTypes/Unify.elm +++ b/src/Stage/InferTypes/Unify.elm @@ -187,6 +187,9 @@ unifyTypes t1 t2 aliases substitutionMap = Just aliasedType -> unifyTypes (ConcreteType.toType aliasedType) t2 aliases substitutionMap + ( Shader _, _ ) -> + err + unifyVariable : Int @@ -271,3 +274,6 @@ occurs id typeOrId substitutionMap = UserDefinedType { args } -> List.any f args + + Shader _ -> + False diff --git a/src/Stage/Parse/Parser.elm b/src/Stage/Parse/Parser.elm index 3ecf3e91..22affb20 100644 --- a/src/Stage/Parse/Parser.elm +++ b/src/Stage/Parse/Parser.elm @@ -17,6 +17,7 @@ module Stage.Parse.Parser exposing import Dict exposing (Dict) import Elm.AST.Frontend as Frontend exposing (Expr(..), LocatedExpr, LocatedPattern, Pattern(..)) +import Elm.AST.Shader as Shader import Elm.Compiler.Error exposing ( Error(..) @@ -541,6 +542,7 @@ expr = , lambda , PP.literal literal , always var + , always shader , list , parenStartingExpr , record @@ -1450,6 +1452,135 @@ case_ config = |> located +shader : Parser_ LocatedExpr +shader = + P.succeed (Frontend.Shader "TODO") + |. P.symbol (P.Token "[glsl|" ShaderProblem) + -- |= P.getChompedString (P.chompUntil (P.Token "|]" ShaderProblem)) + |= glslParser + |. P.symbol (P.Token "|]" ShaderProblem) + -- |> P.andThen shaderTypes + |> located + + +shaderTypes : String -> Parser_ Expr +shaderTypes value = + case P.run glslParser value of + Ok types -> + P.succeed (Frontend.Shader value types) + + Err err -> + P.problem ShaderProblem + + +glslParser : + Parser_ + { attribute : Dict String Shader.Type + , uniform : Dict String Shader.Type + , varying : Dict String Shader.Type + } +glslParser = + P.loop { attribute = Dict.empty, uniform = Dict.empty, varying = Dict.empty } glslParserHelp + + +glslParserHelp : + { attribute : Dict String Shader.Type + , uniform : Dict String Shader.Type + , varying : Dict String Shader.Type + } + -> + Parser_ + (P.Step + { attribute : Dict String Shader.Type + , uniform : Dict String Shader.Type + , varying : Dict String Shader.Type + } + { attribute : Dict String Shader.Type + , uniform : Dict String Shader.Type + , varying : Dict String Shader.Type + } + ) +glslParserHelp types = + P.succeed identity + |. P.spaces + |= P.oneOf + [ P.succeed + (\attributeName attributeType -> + P.Loop + { types + | attribute = Dict.insert attributeName attributeType types.attribute + } + ) + |. P.keyword (P.Token "attribute" ShaderProblem) + |. P.spaces + |= glslVarName + |. P.spaces + |= glslTypeParser + |. P.chompUntil (P.Token "\n" ShaderProblem) + , P.succeed + (\uniformName uniformType -> + P.Loop + { types + | uniform = Dict.insert uniformName uniformType types.uniform + } + ) + |. P.keyword (P.Token "uniform" ShaderProblem) + |. P.spaces + |= glslVarName + |. P.spaces + |= glslTypeParser + |. P.chompUntil (P.Token "\n" ShaderProblem) + , P.succeed + (\varyingName varyingType -> + P.Loop + { types + | varying = Dict.insert varyingName varyingType types.varying + } + ) + |. P.keyword (P.Token "varying" ShaderProblem) + |. P.spaces + |= glslVarName + |. P.spaces + |= glslTypeParser + |. P.chompUntil (P.Token "\n" ShaderProblem) + , P.succeed () + |. P.chompUntil (P.Token "\n" ShaderProblem) + |> P.map (\_ -> P.Loop types) + , P.succeed () + |> P.map (\_ -> P.Done types) + ] + + +glslVarName : Parser_ String +glslVarName = + P.variable + { start = Char.isLower + , inner = \c -> Char.isAlphaNum c || c == '_' + , reserved = Set.empty + , expecting = ShaderProblem + } + + +glslTypeParser : Parser_ Shader.Type +glslTypeParser = + P.oneOf + [ P.succeed Shader.Int + |. P.keyword (P.Token "int" ShaderProblem) + , P.succeed Shader.Float + |. P.keyword (P.Token "float" ShaderProblem) + , P.succeed Shader.V2 + |. P.keyword (P.Token "vec2" ShaderProblem) + , P.succeed Shader.V3 + |. P.keyword (P.Token "vec3" ShaderProblem) + , P.succeed Shader.V4 + |. P.keyword (P.Token "vec4" ShaderProblem) + , P.succeed Shader.M4 + |. P.keyword (P.Token "mat4" ShaderProblem) + , P.succeed Shader.Texture + |. P.keyword (P.Token "sampler2D" ShaderProblem) + ] + + caseBranch : ExprConfig -> Parser_ { pattern : LocatedPattern, body : LocatedExpr } caseBranch config = P.succeed diff --git a/tests/InferTypesFuzz.elm b/tests/InferTypesFuzz.elm index 4244a58e..4dcf2a10 100644 --- a/tests/InferTypesFuzz.elm +++ b/tests/InferTypesFuzz.elm @@ -406,6 +406,10 @@ shrinkExpr expr = -- TODO take a stab at this? Do we actually even generate these? nope + CanonicalU.Shader _ -> + -- TODO take a stab at this? Do we actually even generate these? + nope + {-| Shrinks a plus expression. diff --git a/tests/InferTypesTest.elm b/tests/InferTypesTest.elm index eed1ff46..bc4b09e7 100644 --- a/tests/InferTypesTest.elm +++ b/tests/InferTypesTest.elm @@ -3,6 +3,7 @@ module InferTypesTest exposing (isParametric, niceVarName, typeInference, typeTo import Dict import Elm.AST.Canonical as Canonical import Elm.AST.Canonical.Unwrapped as CanonicalU +import Elm.AST.Shader as Shader import Elm.AST.Typed as Typed import Elm.Compiler.Error as Error exposing (Error(..), TypeError(..)) import Elm.Data.Qualifiedness exposing (PossiblyQualified(..), Qualified(..)) @@ -191,6 +192,33 @@ typeInference = ) ) ] + , runSection "shader" + [ ( "simple example" + , CanonicalU.Shader """ + +attribute vec3 position; +attribute vec3 color; +uniform mat4 perspective; +varying vec3 vcolor; +void main () { + gl_Position = perspective * vec4(position, 1.0); + vcolor = color; +} + +""" + , Ok + (Shader + { attribute = + Dict.fromList + [ ( "position", Shader.V3 ) + , ( "color", Shader.V3 ) + ] + , uniform = Dict.fromList [ ( "perspective", Shader.M4 ) ] + , varying = Dict.fromList [ ( "vcolor", Shader.V3 ) ] + } + ) + ) + ] ] diff --git a/tests/ParserTest.elm b/tests/ParserTest.elm index b8a0d4d3..ff1a71d3 100644 --- a/tests/ParserTest.elm +++ b/tests/ParserTest.elm @@ -14,6 +14,7 @@ module ParserTest exposing import Dict import Elm.AST.Frontend as Frontend import Elm.AST.Frontend.Unwrapped exposing (Expr(..), Pattern(..)) +import Elm.AST.Shader as Shader import Elm.Compiler.Error exposing (ParseContext, ParseProblem) import Elm.Data.Declaration as Declaration exposing (DeclarationBody) import Elm.Data.Exposing exposing (ExposedItem(..), Exposing(..)) @@ -1268,7 +1269,7 @@ expr = , ( "multiline" , """ { a = 42 - , b = "hello" + , b = "hello" } """ , Just @@ -1357,6 +1358,89 @@ expr = ) ] ) + , ( "shader" + , [ ( "simple case" + , "[glsl|...|]" + , Just + (Shader "..." + { attribute = Dict.empty + , uniform = Dict.empty + , varying = Dict.empty + } + ) + ) + , ( "vertexShader" + , """ + [glsl| + + attribute vec3 position; + attribute vec3 color; + uniform mat4 perspective; + varying vec3 vcolor; + void main () { + gl_Position = perspective * vec4(position, 1.0); + vcolor = color; + } + + |] + """ + |> String.unindent + |> String.removeNewlinesAtEnds + , Just + (Shader """ + + attribute vec3 position; + attribute vec3 color; + uniform mat4 perspective; + varying vec3 vcolor; + void main () { + gl_Position = perspective * vec4(position, 1.0); + vcolor = color; + } + +""" + { attribute = + Dict.fromList + [ ( "position", Shader.V3 ) + , ( "color", Shader.V3 ) + ] + , uniform = Dict.singleton "perspective" Shader.M4 + , varying = Dict.singleton "vcolor" Shader.V3 + } + ) + ) + , ( "fragmentShader" + , """ + [glsl| + + precision mediump float; + varying vec3 vcolor; + void main () { + gl_FragColor = vec4(vcolor, 1.0); + } + + |] + """ + |> String.unindent + |> String.removeNewlinesAtEnds + , Just + (Shader """ + + precision mediump float; + varying vec3 vcolor; + void main () { + gl_FragColor = vec4(vcolor, 1.0); + } + +""" + { attribute = Dict.empty + , uniform = Dict.empty + , varying = Dict.singleton "vcolor" Shader.V3 + } + ) + ) + ] + ) ] ) @@ -1545,7 +1629,7 @@ type_ = , ( "multiline record" , """ { x : Int - , y : String + , y : String } """ |> String.unindent