hydra-0.15.0: src/main/haskell/Hydra/Sources/Go/Syntax.hs
module Hydra.Sources.Go.Syntax where
-- Standard imports for type-level sources outside of the kernel
import Hydra.Kernel hiding (literalType)
import Hydra.Dsl.Annotations
import Hydra.Dsl.Bootstrap
import Hydra.Dsl.Types ((>:))
import qualified Hydra.Dsl.Types as T
import qualified Hydra.Sources.Kernel.Types.Core as Core
import qualified Data.List as L
import qualified Data.Map as M
import qualified Data.Set as S
import qualified Data.Maybe as Y
ns :: Namespace
ns = Namespace "hydra.go.syntax"
define :: String -> Type -> Binding
define = datatype ns
go :: String -> Type
go = typeref ns
module_ :: Module
module_ = Module {
moduleNamespace = ns,
moduleDefinitions = (map toTypeDef definitions),
moduleTermDependencies = [Core.ns],
moduleTypeDependencies = [Core.ns],
moduleDescription = Just ("A Go syntax model, based on the Go Language Specification retrieved on 2025-02-05"
++ " from https://go.dev/ref/spec")}
where
definitions = constructs ++ terminals ++ sourceFile ++ declarations ++ types
++ expressions ++ statements ++ miscellaneous
-- These definitions are not based on the grammar, but are convenient for working with Go sources in Hydra.
constructs = [
annotatedDeclaration,
goModule]
-- Terminal tokens
terminals = [
identifier,
intLit,
floatLit,
imaginaryLit,
runeLit,
stringLit,
rawStringLit,
interpretedStringLit]
-- Source file structure
sourceFile = [
sourceFile_,
packageClause,
importDecl,
importSpec,
importAlias,
importPath]
-- Declarations
declarations = [
declaration,
topLevelDecl,
constDecl,
constSpec,
varDecl,
varSpec,
shortVarDecl,
typeDecl,
typeSpec,
aliasDecl,
typeDef,
typeParameters,
typeParamDecl,
typeConstraint,
functionDecl,
functionBody,
methodDecl,
receiver]
-- Types
types = [
type_,
typeName,
qualifiedIdent,
typeLit,
arrayType,
sliceType,
structType,
fieldDecl,
namedField,
embeddedField,
tag,
pointerType,
functionType,
signature,
result,
parameters,
parameterDecl,
interfaceType,
interfaceElem,
methodElem,
typeElem,
typeTerm,
mapType,
channelType,
channelDirection]
-- Expressions
expressions = [
expression,
unaryExpr,
unaryOperation,
binaryExpr,
binaryOp,
primaryExpr,
selectorExpr,
indexExpr,
sliceExpr,
typeAssertionExpr,
callExpr,
operand,
operandName,
literal,
basicLit,
compositeLit,
literalType,
literalValue,
elementList,
keyedElement,
key,
element,
functionLit,
selector,
index,
slice_,
simpleSlice,
fullSlice,
typeAssertion,
arguments,
methodExpr,
conversion]
-- Statements
statements = [
statement,
simpleStmt,
emptyStmt,
labeledStmt,
expressionStmt,
sendStmt,
incDecStmt,
assignment,
assignOp,
ifStmt,
elseClause,
switchStmt,
exprSwitchStmt,
exprCaseClause,
typeSwitchStmt,
typeSwitchGuard,
typeCaseClause,
forStmt,
forClauseOrRange,
forClause,
rangeClause,
rangeVars,
goStmt,
selectStmt,
commClause,
commCase,
receiveCase,
returnStmt,
breakStmt,
continueStmt,
gotoStmt,
fallthroughStmt,
deferStmt,
block]
-- Miscellaneous
miscellaneous = [
unaryOp,
mulOp,
addOp,
relOp]
-- ============================================================================
-- Constructs (Hydra-specific, not from grammar)
-- ============================================================================
annotatedDeclaration :: Binding
annotatedDeclaration = define "AnnotatedDeclaration" $ T.record [
"comment">: T.string,
"declaration">: go "TopLevelDecl"]
goModule :: Binding
goModule = define "Module" $ T.record [
"package">: go "PackageClause",
"imports">: T.list $ go "ImportDecl",
"declarations">: T.list $ go "TopLevelDecl"]
-- ============================================================================
-- Terminals
-- ============================================================================
-- identifier = letter { letter | unicode_digit } .
identifier :: Binding
identifier = define "Identifier" $ T.wrap T.string
-- int_lit = decimal_lit | binary_lit | octal_lit | hex_lit .
-- decimal_lit = "0" | ( "1" … "9" ) [ [ "_" ] decimal_digits ] .
-- binary_lit = "0" ( "b" | "B" ) [ "_" ] binary_digits .
-- octal_lit = "0" [ "o" | "O" ] [ "_" ] octal_digits .
-- hex_lit = "0" ( "x" | "X" ) [ "_" ] hex_digits .
intLit :: Binding
intLit = define "IntLit" $ T.wrap T.bigint
-- float_lit = decimal_float_lit | hex_float_lit .
-- decimal_float_lit = decimal_digits "." [ decimal_digits ] [ decimal_exponent ] |
-- decimal_digits decimal_exponent |
-- "." decimal_digits [ decimal_exponent ] .
-- hex_float_lit = "0" ( "x" | "X" ) hex_mantissa hex_exponent .
floatLit :: Binding
floatLit = define "FloatLit" $ T.wrap T.float64
-- imaginary_lit = (decimal_digits | int_lit | float_lit) "i" .
imaginaryLit :: Binding
imaginaryLit = define "ImaginaryLit" $ T.wrap T.float64
-- rune_lit = "'" ( unicode_value | byte_value ) "'" .
runeLit :: Binding
runeLit = define "RuneLit" $ T.wrap T.int32 -- rune is int32
-- string_lit = raw_string_lit | interpreted_string_lit .
stringLit :: Binding
stringLit = define "StringLit" $ T.union [
"raw">: go "RawStringLit",
"interpreted">: go "InterpretedStringLit"]
-- raw_string_lit = "`" { unicode_char | newline } "`" .
rawStringLit :: Binding
rawStringLit = define "RawStringLit" $ T.wrap T.string
-- interpreted_string_lit = `"` { unicode_value | byte_value } `"` .
interpretedStringLit :: Binding
interpretedStringLit = define "InterpretedStringLit" $ T.wrap T.string
-- ============================================================================
-- Source file structure
-- ============================================================================
-- SourceFile = PackageClause ";" { ImportDecl ";" } { TopLevelDecl ";" } .
sourceFile_ :: Binding
sourceFile_ = define "SourceFile" $ T.record [
"package">: go "PackageClause",
"imports">: T.list $ go "ImportDecl",
"declarations">: T.list $ go "TopLevelDecl"]
-- PackageClause = "package" PackageName .
-- PackageName = identifier .
packageClause :: Binding
packageClause = define "PackageClause" $ T.wrap $ go "Identifier"
-- ImportDecl = "import" ( ImportSpec | "(" { ImportSpec ";" } ")" ) .
importDecl :: Binding
importDecl = define "ImportDecl" $ T.wrap $ nonemptyList $ go "ImportSpec"
-- ImportSpec = [ "." | PackageName ] ImportPath .
importSpec :: Binding
importSpec = define "ImportSpec" $ T.record [
"alias">: T.maybe $ go "ImportAlias",
"path">: go "ImportPath"]
-- Hydra: ImportAlias represents the optional alias in an import
-- Either "." for dot import, or an identifier for named alias
importAlias :: Binding
importAlias = define "ImportAlias" $ T.union [
"dot">: T.unit,
"name">: go "Identifier"]
-- ImportPath = string_lit .
importPath :: Binding
importPath = define "ImportPath" $ T.wrap $ go "StringLit"
-- ============================================================================
-- Declarations
-- ============================================================================
-- Declaration = ConstDecl | TypeDecl | VarDecl .
declaration :: Binding
declaration = define "Declaration" $ T.union [
"const">: go "ConstDecl",
"type">: go "TypeDecl",
"var">: go "VarDecl"]
-- TopLevelDecl = Declaration | FunctionDecl | MethodDecl .
topLevelDecl :: Binding
topLevelDecl = define "TopLevelDecl" $ T.union [
"declaration">: go "Declaration",
"function">: go "FunctionDecl",
"method">: go "MethodDecl"]
-- ConstDecl = "const" ( ConstSpec | "(" { ConstSpec ";" } ")" ) .
constDecl :: Binding
constDecl = define "ConstDecl" $ T.wrap $ nonemptyList $ go "ConstSpec"
-- ConstSpec = IdentifierList [ [ Type ] "=" ExpressionList ] .
constSpec :: Binding
constSpec = define "ConstSpec" $ T.record [
"names">: nonemptyList $ go "Identifier",
"type">: T.maybe $ go "Type",
"values">: T.list $ go "Expression"]
-- VarDecl = "var" ( VarSpec | "(" { VarSpec ";" } ")" ) .
varDecl :: Binding
varDecl = define "VarDecl" $ T.wrap $ nonemptyList $ go "VarSpec"
-- VarSpec = IdentifierList ( Type [ "=" ExpressionList ] | "=" ExpressionList ) .
varSpec :: Binding
varSpec = define "VarSpec" $ T.record [
"names">: nonemptyList $ go "Identifier",
"type">: T.maybe $ go "Type",
"values">: T.list $ go "Expression"]
-- ShortVarDecl = IdentifierList ":=" ExpressionList .
shortVarDecl :: Binding
shortVarDecl = define "ShortVarDecl" $ T.record [
"names">: nonemptyList $ go "Identifier",
"values">: nonemptyList $ go "Expression"]
-- TypeDecl = "type" ( TypeSpec | "(" { TypeSpec ";" } ")" ) .
typeDecl :: Binding
typeDecl = define "TypeDecl" $ T.wrap $ nonemptyList $ go "TypeSpec"
-- TypeSpec = AliasDecl | TypeDef .
typeSpec :: Binding
typeSpec = define "TypeSpec" $ T.union [
"alias">: go "AliasDecl",
"definition">: go "TypeDef"]
-- AliasDecl = identifier "=" Type .
aliasDecl :: Binding
aliasDecl = define "AliasDecl" $ T.record [
"name">: go "Identifier",
"type">: go "Type"]
-- TypeDef = identifier [ TypeParameters ] Type .
typeDef :: Binding
typeDef = define "TypeDef" $ T.record [
"name">: go "Identifier",
"typeParams">: T.maybe $ go "TypeParameters",
"type">: go "Type"]
-- TypeParameters = "[" TypeParamList [ "," ] "]" .
-- TypeParamList = TypeParamDecl { "," TypeParamDecl } .
typeParameters :: Binding
typeParameters = define "TypeParameters" $ T.wrap $ nonemptyList $ go "TypeParamDecl"
-- TypeParamDecl = IdentifierList TypeConstraint .
typeParamDecl :: Binding
typeParamDecl = define "TypeParamDecl" $ T.record [
"names">: nonemptyList $ go "Identifier",
"constraint">: go "TypeConstraint"]
-- TypeConstraint = TypeElem .
typeConstraint :: Binding
typeConstraint = define "TypeConstraint" $ T.wrap $ go "TypeElem"
-- FunctionDecl = "func" FunctionName [ TypeParameters ] Signature [ FunctionBody ] .
-- FunctionName = identifier .
functionDecl :: Binding
functionDecl = define "FunctionDecl" $ T.record [
"name">: go "Identifier",
"typeParams">: T.maybe $ go "TypeParameters",
"signature">: go "Signature",
"body">: T.maybe $ go "FunctionBody"]
-- FunctionBody = Block .
functionBody :: Binding
functionBody = define "FunctionBody" $ T.wrap $ go "Block"
-- MethodDecl = "func" Receiver MethodName Signature [ FunctionBody ] .
-- MethodName = identifier .
methodDecl :: Binding
methodDecl = define "MethodDecl" $ T.record [
"receiver">: go "Receiver",
"name">: go "Identifier",
"signature">: go "Signature",
"body">: T.maybe $ go "FunctionBody"]
-- Receiver = Parameters .
-- (Note: Go spec says the receiver must be a single non-variadic parameter)
receiver :: Binding
receiver = define "Receiver" $ T.record [
"name">: T.maybe $ go "Identifier",
"type">: go "Type"]
-- ============================================================================
-- Types
-- ============================================================================
-- Type = TypeName [ TypeArgs ] | TypeLit | "(" Type ")" .
type_ :: Binding
type_ = define "Type" $ T.union [
"name">: go "TypeName",
"literal">: go "TypeLit",
"paren">: go "Type"]
-- TypeName = identifier | QualifiedIdent .
typeName :: Binding
typeName = define "TypeName" $ T.record [
"name">: go "QualifiedIdent",
"typeArgs">: T.list $ go "Type"]
-- QualifiedIdent = PackageName "." identifier .
qualifiedIdent :: Binding
qualifiedIdent = define "QualifiedIdent" $ T.record [
"package">: T.maybe $ go "Identifier",
"name">: go "Identifier"]
-- TypeLit = ArrayType | StructType | PointerType | FunctionType | InterfaceType |
-- SliceType | MapType | ChannelType .
typeLit :: Binding
typeLit = define "TypeLit" $ T.union [
"array">: go "ArrayType",
"struct">: go "StructType",
"pointer">: go "PointerType",
"function">: go "FunctionType",
"interface">: go "InterfaceType",
"slice">: go "SliceType",
"map">: go "MapType",
"channel">: go "ChannelType"]
-- ArrayType = "[" ArrayLength "]" ElementType .
-- ArrayLength = Expression .
-- ElementType = Type .
arrayType :: Binding
arrayType = define "ArrayType" $ T.record [
"length">: go "Expression",
"element">: go "Type"]
-- SliceType = "[" "]" ElementType .
sliceType :: Binding
sliceType = define "SliceType" $ T.wrap $ go "Type"
-- StructType = "struct" "{" { FieldDecl ";" } "}" .
structType :: Binding
structType = define "StructType" $ T.wrap $ T.list $ go "FieldDecl"
-- FieldDecl = (IdentifierList Type | EmbeddedField) [ Tag ] .
-- EmbeddedField = [ "*" ] TypeName [ TypeArgs ] .
fieldDecl :: Binding
fieldDecl = define "FieldDecl" $ T.union [
"named">: go "NamedField",
"embedded">: go "EmbeddedField"]
-- Hydra: Named field with names, type, and optional tag
namedField :: Binding
namedField = define "NamedField" $ T.record [
"names">: nonemptyList $ go "Identifier",
"type">: go "Type",
"tag">: T.maybe $ go "Tag"]
-- Hydra: Embedded field (anonymous field)
embeddedField :: Binding
embeddedField = define "EmbeddedField" $ T.record [
"pointer">: T.boolean,
"type">: go "TypeName",
"tag">: T.maybe $ go "Tag"]
-- Tag = string_lit .
tag :: Binding
tag = define "Tag" $ T.wrap $ go "StringLit"
-- PointerType = "*" BaseType .
-- BaseType = Type .
pointerType :: Binding
pointerType = define "PointerType" $ T.wrap $ go "Type"
-- FunctionType = "func" Signature .
functionType :: Binding
functionType = define "FunctionType" $ T.wrap $ go "Signature"
-- Signature = Parameters [ Result ] .
signature :: Binding
signature = define "Signature" $ T.record [
"parameters">: go "Parameters",
"result">: T.maybe $ go "Result"]
-- Result = Parameters | Type .
result :: Binding
result = define "Result" $ T.union [
"parameters">: go "Parameters",
"type">: go "Type"]
-- Parameters = "(" [ ParameterList [ "," ] ] ")" .
-- ParameterList = ParameterDecl { "," ParameterDecl } .
parameters :: Binding
parameters = define "Parameters" $ T.wrap $ T.list $ go "ParameterDecl"
-- ParameterDecl = [ IdentifierList ] [ "..." ] Type .
parameterDecl :: Binding
parameterDecl = define "ParameterDecl" $ T.record [
"names">: T.list $ go "Identifier",
"variadic">: T.boolean,
"type">: go "Type"]
-- InterfaceType = "interface" "{" { InterfaceElem ";" } "}" .
interfaceType :: Binding
interfaceType = define "InterfaceType" $ T.wrap $ T.list $ go "InterfaceElem"
-- InterfaceElem = MethodElem | TypeElem .
interfaceElem :: Binding
interfaceElem = define "InterfaceElem" $ T.union [
"method">: go "MethodElem",
"type">: go "TypeElem"]
-- MethodElem = MethodName Signature .
methodElem :: Binding
methodElem = define "MethodElem" $ T.record [
"name">: go "Identifier",
"signature">: go "Signature"]
-- TypeElem = TypeTerm { "|" TypeTerm } .
typeElem :: Binding
typeElem = define "TypeElem" $ T.wrap $ nonemptyList $ go "TypeTerm"
-- TypeTerm = Type | UnderlyingType .
-- UnderlyingType = "~" Type .
typeTerm :: Binding
typeTerm = define "TypeTerm" $ T.record [
"underlying">: T.boolean, -- true if ~Type
"type">: go "Type"]
-- MapType = "map" "[" KeyType "]" ElementType .
-- KeyType = Type .
mapType :: Binding
mapType = define "MapType" $ T.record [
"key">: go "Type",
"value">: go "Type"]
-- ChannelType = ( "chan" | "chan" "<-" | "<-" "chan" ) ElementType .
channelType :: Binding
channelType = define "ChannelType" $ T.record [
"direction">: go "ChannelDirection",
"element">: go "Type"]
channelDirection :: Binding
channelDirection = define "ChannelDirection" $ T.enum [
"bidirectional", -- chan
"send", -- chan<-
"receive"] -- <-chan
-- ============================================================================
-- Expressions
-- ============================================================================
-- Expression = UnaryExpr | Expression binary_op Expression .
expression :: Binding
expression = define "Expression" $ T.union [
"unary">: go "UnaryExpr",
"binary">: go "BinaryExpr"]
-- UnaryExpr = PrimaryExpr | unary_op UnaryExpr .
unaryExpr :: Binding
unaryExpr = define "UnaryExpr" $ T.union [
"primary">: go "PrimaryExpr",
"op">: go "UnaryOperation"]
-- Hydra: Unary operation with operator and operand
unaryOperation :: Binding
unaryOperation = define "UnaryOperation" $ T.record [
"op">: go "UnaryOp",
"operand">: go "UnaryExpr"]
-- binary_op = "||" | "&&" | rel_op | add_op | mul_op .
binaryExpr :: Binding
binaryExpr = define "BinaryExpr" $ T.record [
"left">: go "Expression",
"op">: go "BinaryOp",
"right">: go "Expression"]
binaryOp :: Binding
binaryOp = define "BinaryOp" $ T.enum [
-- Logical
"or", -- ||
"and", -- &&
-- Relational
"equal", -- ==
"notEqual", -- !=
"less", -- <
"lessEqual", -- <=
"greater", -- >
"greaterEqual", -- >=
-- Additive
"add", -- +
"subtract", -- -
"bitwiseOr", -- |
"bitwiseXor", -- ^
-- Multiplicative
"multiply", -- *
"divide", -- /
"remainder", -- %
"leftShift", -- <<
"rightShift", -- >>
"bitwiseAnd", -- &
"bitClear"] -- &^
-- PrimaryExpr =
-- Operand |
-- Conversion |
-- MethodExpr |
-- PrimaryExpr Selector |
-- PrimaryExpr Index |
-- PrimaryExpr Slice |
-- PrimaryExpr TypeAssertion |
-- PrimaryExpr Arguments .
primaryExpr :: Binding
primaryExpr = define "PrimaryExpr" $ T.union [
"operand">: go "Operand",
"conversion">: go "Conversion",
"methodExpr">: go "MethodExpr",
"selector">: go "SelectorExpr",
"index">: go "IndexExpr",
"slice">: go "SliceExpr",
"typeAssertion">: go "TypeAssertionExpr",
"call">: go "CallExpr"]
-- Hydra: Selector expression (x.y)
selectorExpr :: Binding
selectorExpr = define "SelectorExpr" $ T.record [
"expr">: go "PrimaryExpr",
"selector">: go "Identifier"]
-- Hydra: Index expression (x[i])
indexExpr :: Binding
indexExpr = define "IndexExpr" $ T.record [
"expr">: go "PrimaryExpr",
"index">: go "Expression"]
-- Hydra: Slice expression (x[lo:hi] or x[lo:hi:max])
sliceExpr :: Binding
sliceExpr = define "SliceExpr" $ T.record [
"expr">: go "PrimaryExpr",
"slice">: go "Slice"]
-- Hydra: Type assertion expression (x.(T))
typeAssertionExpr :: Binding
typeAssertionExpr = define "TypeAssertionExpr" $ T.record [
"expr">: go "PrimaryExpr",
"type">: go "Type"]
-- Hydra: Call expression (f(args))
callExpr :: Binding
callExpr = define "CallExpr" $ T.record [
"function">: go "PrimaryExpr",
"arguments">: go "Arguments"]
-- Operand = Literal | OperandName [ TypeArgs ] | "(" Expression ")" .
-- OperandName = identifier | QualifiedIdent .
operand :: Binding
operand = define "Operand" $ T.union [
"literal">: go "Literal",
"name">: go "OperandName",
"paren">: go "Expression"]
-- Hydra: Operand name with optional type arguments
operandName :: Binding
operandName = define "OperandName" $ T.record [
"name">: go "QualifiedIdent",
"typeArgs">: T.list $ go "Type"]
-- Literal = BasicLit | CompositeLit | FunctionLit .
literal :: Binding
literal = define "Literal" $ T.union [
"basic">: go "BasicLit",
"composite">: go "CompositeLit",
"function">: go "FunctionLit"]
-- BasicLit = int_lit | float_lit | imaginary_lit | rune_lit | string_lit .
basicLit :: Binding
basicLit = define "BasicLit" $ T.union [
"int">: go "IntLit",
"float">: go "FloatLit",
"imaginary">: go "ImaginaryLit",
"rune">: go "RuneLit",
"string">: go "StringLit"]
-- CompositeLit = LiteralType LiteralValue .
compositeLit :: Binding
compositeLit = define "CompositeLit" $ T.record [
"type">: go "LiteralType",
"value">: go "LiteralValue"]
-- LiteralType = StructType | ArrayType | "[" "..." "]" ElementType |
-- SliceType | MapType | TypeName [ TypeArgs ] .
literalType :: Binding
literalType = define "LiteralType" $ T.union [
"struct">: go "StructType",
"array">: go "ArrayType",
"inferredArray">: go "Type", -- [...]T
"slice">: go "SliceType",
"map">: go "MapType",
"name">: go "TypeName"]
-- LiteralValue = "{" [ ElementList [ "," ] ] "}" .
literalValue :: Binding
literalValue = define "LiteralValue" $ T.wrap $ T.list $ go "KeyedElement"
-- ElementList = KeyedElement { "," KeyedElement } .
elementList :: Binding
elementList = define "ElementList" $ T.wrap $ nonemptyList $ go "KeyedElement"
-- KeyedElement = [ Key ":" ] Element .
keyedElement :: Binding
keyedElement = define "KeyedElement" $ T.record [
"key">: T.maybe $ go "Key",
"element">: go "Element"]
-- Key = FieldName | Expression | LiteralValue .
-- FieldName = identifier .
key :: Binding
key = define "Key" $ T.union [
"field">: go "Identifier",
"expression">: go "Expression",
"literal">: go "LiteralValue"]
-- Element = Expression | LiteralValue .
element :: Binding
element = define "Element" $ T.union [
"expression">: go "Expression",
"literal">: go "LiteralValue"]
-- FunctionLit = "func" Signature FunctionBody .
functionLit :: Binding
functionLit = define "FunctionLit" $ T.record [
"signature">: go "Signature",
"body">: go "FunctionBody"]
-- Selector = "." identifier .
selector :: Binding
selector = define "Selector" $ T.wrap $ go "Identifier"
-- Index = "[" Expression [ "," ] "]" .
index :: Binding
index = define "Index" $ T.wrap $ nonemptyList $ go "Expression"
-- Slice = "[" [ Expression ] ":" [ Expression ] "]" |
-- "[" [ Expression ] ":" Expression ":" Expression "]" .
slice_ :: Binding
slice_ = define "Slice" $ T.union [
"simple">: go "SimpleSlice",
"full">: go "FullSlice"]
-- Hydra: Simple slice [lo:hi]
simpleSlice :: Binding
simpleSlice = define "SimpleSlice" $ T.record [
"low">: T.maybe $ go "Expression",
"high">: T.maybe $ go "Expression"]
-- Hydra: Full slice [lo:hi:max]
fullSlice :: Binding
fullSlice = define "FullSlice" $ T.record [
"low">: T.maybe $ go "Expression",
"high">: go "Expression",
"max">: go "Expression"]
-- TypeAssertion = "." "(" Type ")" .
typeAssertion :: Binding
typeAssertion = define "TypeAssertion" $ T.wrap $ go "Type"
-- Arguments = "(" [ ( ExpressionList | Type [ "," ExpressionList ] ) [ "..." ] [ "," ] ] ")" .
arguments :: Binding
arguments = define "Arguments" $ T.record [
"typeArg">: T.maybe $ go "Type",
"expressions">: T.list $ go "Expression",
"ellipsis">: T.boolean]
-- MethodExpr = ReceiverType "." MethodName .
-- ReceiverType = Type .
methodExpr :: Binding
methodExpr = define "MethodExpr" $ T.record [
"receiver">: go "Type",
"method">: go "Identifier"]
-- Conversion = Type "(" Expression [ "," ] ")" .
conversion :: Binding
conversion = define "Conversion" $ T.record [
"type">: go "Type",
"expression">: go "Expression"]
-- ============================================================================
-- Statements
-- ============================================================================
-- Statement =
-- Declaration | LabeledStmt | SimpleStmt |
-- GoStmt | ReturnStmt | BreakStmt | ContinueStmt | GotoStmt |
-- FallthroughStmt | Block | IfStmt | SwitchStmt | SelectStmt | ForStmt |
-- DeferStmt .
statement :: Binding
statement = define "Statement" $ T.union [
"declaration">: go "Declaration",
"labeled">: go "LabeledStmt",
"simple">: go "SimpleStmt",
"go">: go "GoStmt",
"return">: go "ReturnStmt",
"break">: go "BreakStmt",
"continue">: go "ContinueStmt",
"goto">: go "GotoStmt",
"fallthrough">: go "FallthroughStmt",
"block">: go "Block",
"if">: go "IfStmt",
"switch">: go "SwitchStmt",
"select">: go "SelectStmt",
"for">: go "ForStmt",
"defer">: go "DeferStmt"]
-- SimpleStmt = EmptyStmt | ExpressionStmt | SendStmt | IncDecStmt | Assignment | ShortVarDecl .
simpleStmt :: Binding
simpleStmt = define "SimpleStmt" $ T.union [
"empty">: go "EmptyStmt",
"expression">: go "ExpressionStmt",
"send">: go "SendStmt",
"incDec">: go "IncDecStmt",
"assignment">: go "Assignment",
"shortVarDecl">: go "ShortVarDecl"]
-- EmptyStmt = .
emptyStmt :: Binding
emptyStmt = define "EmptyStmt" $ T.wrap T.unit
-- LabeledStmt = Label ":" Statement .
-- Label = identifier .
labeledStmt :: Binding
labeledStmt = define "LabeledStmt" $ T.record [
"label">: go "Identifier",
"statement">: go "Statement"]
-- ExpressionStmt = Expression .
expressionStmt :: Binding
expressionStmt = define "ExpressionStmt" $ T.wrap $ go "Expression"
-- SendStmt = Channel "<-" Expression .
-- Channel = Expression .
sendStmt :: Binding
sendStmt = define "SendStmt" $ T.record [
"channel">: go "Expression",
"value">: go "Expression"]
-- IncDecStmt = Expression ( "++" | "--" ) .
incDecStmt :: Binding
incDecStmt = define "IncDecStmt" $ T.record [
"expression">: go "Expression",
"increment">: T.boolean] -- true for ++, false for --
-- Assignment = ExpressionList assign_op ExpressionList .
assignment :: Binding
assignment = define "Assignment" $ T.record [
"lhs">: nonemptyList $ go "Expression",
"op">: go "AssignOp",
"rhs">: nonemptyList $ go "Expression"]
-- assign_op = [ add_op | mul_op ] "=" .
assignOp :: Binding
assignOp = define "AssignOp" $ T.union [
"simple">: T.unit, -- =
"add">: go "AddOp", -- +=, -=, |=, ^=
"mul">: go "MulOp"] -- *=, /=, %=, <<=, >>=, &=, &^=
-- IfStmt = "if" [ SimpleStmt ";" ] Expression Block [ "else" ( IfStmt | Block ) ] .
ifStmt :: Binding
ifStmt = define "IfStmt" $ T.record [
"init">: T.maybe $ go "SimpleStmt",
"condition">: go "Expression",
"then">: go "Block",
"else">: T.maybe $ go "ElseClause"]
-- Hydra: Else clause (either another if or a block)
elseClause :: Binding
elseClause = define "ElseClause" $ T.union [
"if">: go "IfStmt",
"block">: go "Block"]
-- SwitchStmt = ExprSwitchStmt | TypeSwitchStmt .
switchStmt :: Binding
switchStmt = define "SwitchStmt" $ T.union [
"expression">: go "ExprSwitchStmt",
"type">: go "TypeSwitchStmt"]
-- ExprSwitchStmt = "switch" [ SimpleStmt ";" ] [ Expression ] "{" { ExprCaseClause } "}" .
exprSwitchStmt :: Binding
exprSwitchStmt = define "ExprSwitchStmt" $ T.record [
"init">: T.maybe $ go "SimpleStmt",
"expression">: T.maybe $ go "Expression",
"cases">: T.list $ go "ExprCaseClause"]
-- ExprCaseClause = ExprSwitchCase ":" StatementList .
-- ExprSwitchCase = "case" ExpressionList | "default" .
exprCaseClause :: Binding
exprCaseClause = define "ExprCaseClause" $ T.record [
"case">: T.maybe $ nonemptyList $ go "Expression", -- Nothing for default
"statements">: T.list $ go "Statement"]
-- TypeSwitchStmt = "switch" [ SimpleStmt ";" ] TypeSwitchGuard "{" { TypeCaseClause } "}" .
typeSwitchStmt :: Binding
typeSwitchStmt = define "TypeSwitchStmt" $ T.record [
"init">: T.maybe $ go "SimpleStmt",
"guard">: go "TypeSwitchGuard",
"cases">: T.list $ go "TypeCaseClause"]
-- TypeSwitchGuard = [ identifier ":=" ] PrimaryExpr "." "(" "type" ")" .
typeSwitchGuard :: Binding
typeSwitchGuard = define "TypeSwitchGuard" $ T.record [
"name">: T.maybe $ go "Identifier",
"expression">: go "PrimaryExpr"]
-- TypeCaseClause = TypeSwitchCase ":" StatementList .
-- TypeSwitchCase = "case" TypeList | "default" .
-- TypeList = Type { "," Type } .
typeCaseClause :: Binding
typeCaseClause = define "TypeCaseClause" $ T.record [
"case">: T.maybe $ nonemptyList $ go "Type", -- Nothing for default
"statements">: T.list $ go "Statement"]
-- ForStmt = "for" [ Condition | ForClause | RangeClause ] Block .
-- Condition = Expression .
forStmt :: Binding
forStmt = define "ForStmt" $ T.record [
"clause">: T.maybe $ go "ForClauseOrRange",
"body">: go "Block"]
-- Hydra: Either a for clause, range clause, or simple condition
forClauseOrRange :: Binding
forClauseOrRange = define "ForClauseOrRange" $ T.union [
"condition">: go "Expression",
"clause">: go "ForClause",
"range">: go "RangeClause"]
-- ForClause = [ InitStmt ] ";" [ Condition ] ";" [ PostStmt ] .
-- InitStmt = SimpleStmt .
-- PostStmt = SimpleStmt .
forClause :: Binding
forClause = define "ForClause" $ T.record [
"init">: T.maybe $ go "SimpleStmt",
"condition">: T.maybe $ go "Expression",
"post">: T.maybe $ go "SimpleStmt"]
-- RangeClause = [ ExpressionList "=" | IdentifierList ":=" ] "range" Expression .
rangeClause :: Binding
rangeClause = define "RangeClause" $ T.record [
"vars">: T.maybe $ go "RangeVars",
"expression">: go "Expression"]
-- Hydra: Range variables (either assignment or short declaration)
rangeVars :: Binding
rangeVars = define "RangeVars" $ T.union [
"assign">: nonemptyList $ go "Expression",
"declare">: nonemptyList $ go "Identifier"]
-- GoStmt = "go" Expression .
goStmt :: Binding
goStmt = define "GoStmt" $ T.wrap $ go "Expression"
-- SelectStmt = "select" "{" { CommClause } "}" .
selectStmt :: Binding
selectStmt = define "SelectStmt" $ T.wrap $ T.list $ go "CommClause"
-- CommClause = CommCase ":" StatementList .
commClause :: Binding
commClause = define "CommClause" $ T.record [
"case">: go "CommCase",
"statements">: T.list $ go "Statement"]
-- CommCase = "case" ( SendStmt | RecvStmt ) | "default" .
-- RecvStmt = [ ExpressionList "=" | IdentifierList ":=" ] RecvExpr .
-- RecvExpr = Expression .
commCase :: Binding
commCase = define "CommCase" $ T.union [
"send">: go "SendStmt",
"receive">: go "ReceiveCase",
"default">: T.unit]
-- Hydra: Receive case with optional assignment
receiveCase :: Binding
receiveCase = define "ReceiveCase" $ T.record [
"vars">: T.maybe $ go "RangeVars", -- reuse RangeVars type
"expression">: go "Expression"]
-- ReturnStmt = "return" [ ExpressionList ] .
returnStmt :: Binding
returnStmt = define "ReturnStmt" $ T.wrap $ T.list $ go "Expression"
-- BreakStmt = "break" [ Label ] .
breakStmt :: Binding
breakStmt = define "BreakStmt" $ T.wrap $ T.maybe $ go "Identifier"
-- ContinueStmt = "continue" [ Label ] .
continueStmt :: Binding
continueStmt = define "ContinueStmt" $ T.wrap $ T.maybe $ go "Identifier"
-- GotoStmt = "goto" Label .
gotoStmt :: Binding
gotoStmt = define "GotoStmt" $ T.wrap $ go "Identifier"
-- FallthroughStmt = "fallthrough" .
fallthroughStmt :: Binding
fallthroughStmt = define "FallthroughStmt" $ T.wrap T.unit
-- DeferStmt = "defer" Expression .
deferStmt :: Binding
deferStmt = define "DeferStmt" $ T.wrap $ go "Expression"
-- Block = "{" StatementList "}" .
-- StatementList = { Statement ";" } .
block :: Binding
block = define "Block" $ T.wrap $ T.list $ go "Statement"
-- ============================================================================
-- Operators (miscellaneous)
-- ============================================================================
-- unary_op = "+" | "-" | "!" | "^" | "*" | "&" | "<-" .
unaryOp :: Binding
unaryOp = define "UnaryOp" $ T.enum [
"plus", -- +
"minus", -- -
"not", -- !
"xor", -- ^
"deref", -- *
"addressOf", -- &
"receive"] -- <-
-- mul_op = "*" | "/" | "%" | "<<" | ">>" | "&" | "&^" .
mulOp :: Binding
mulOp = define "MulOp" $ T.enum [
"multiply",
"divide",
"remainder",
"leftShift",
"rightShift",
"bitwiseAnd",
"bitClear"]
-- add_op = "+" | "-" | "|" | "^" .
addOp :: Binding
addOp = define "AddOp" $ T.enum [
"add",
"subtract",
"bitwiseOr",
"bitwiseXor"]
-- rel_op = "==" | "!=" | "<" | "<=" | ">" | ">=" .
relOp :: Binding
relOp = define "RelOp" $ T.enum [
"equal",
"notEqual",
"less",
"lessEqual",
"greater",
"greaterEqual"]