@@ -812,124 +812,175 @@ Private Function ParsePrimaryNode(types() As String, vals() As Variant, n As Lon
812812 Set ParsePrimaryNode = bf
813813 Exit Function
814814 End If
815- ' Handle collapsed array-index form IDENT[NUM] (already collapsed by tokenizer)
816- If InStr(name, "[" ) > 0 Then
817- ' keep existing array-index behavior handled elsewhere (or convert into Index node)
818- Dim nm As String : nm = left$(name, InStr(name, "[" ) - 1 )
819- Dim idxS As String : idxS = Mid$(name, InStr(name, "[" ) + 1 , Len(name) - InStr(name, "[" ) - 1 )
820- ' create base variable node
821- Dim baseVar As New Map
822- baseVar.Add "type" , "Variable"
823- baseVar.SetValue "name" , nm
824- ' index node from simple expression string
825- Set idxExpr = ParseExprFromStringToNode(idxS)
826- Set idxNode = New Map
827- idxNode.Add "type" , "Index"
828- idxNode.SetValue "base" , baseVar
829- idxNode.SetValue "index" , idxExpr
830- Set ParsePrimaryNode = idxNode
815+
816+ ' Expression-level anonymous function literal: fun (p1, p2) { ... }
817+ ' This reuses the same 'fun' token used for top-level function declarations but emits
818+ ' a FuncLiteral node usable inside expressions.
819+ If LCase$(name) = "fun" Then
820+ ' advance past 'fun'
821+ idx = idx + 1
822+ ' expect parameter list
823+ Dim params As New Collection
824+ If idx < n And types(idx) = "PAREN" And vals(idx) = "(" Then
825+ idx = idx + 1
826+ Do While idx < n And Not (types(idx) = "PAREN" And vals(idx) = ")" )
827+ If types(idx) = "IDENT" Then
828+ params.Add CStr(vals(idx))
829+ idx = idx + 1
830+ If idx < n And types(idx) = "SEP" And vals(idx) = "," Then idx = idx + 1
831+ ElseIf types(idx) = "SEP" And vals(idx) = "," Then
832+ idx = idx + 1
833+ Else
834+ ' skip unexpected tokens until ')'
835+ idx = idx + 1
836+ End If
837+ Loop
838+ If idx < n And types(idx) = "PAREN" And vals(idx) = ")" Then idx = idx + 1
839+ End If
840+
841+ ' parse body { ... }
842+ If idx < n And types(idx) = "PAREN" And vals(idx) = "{" Then
843+ idx = idx + 1
844+ Dim depthBody As Long : depthBody = 0
845+ Dim bodyTok As New Collection
846+ Do While idx < n
847+ If types(idx) = "PAREN" Then
848+ If vals(idx) = "{" Then
849+ depthBody = depthBody + 1
850+ ElseIf vals(idx) = "}" Then
851+ If depthBody = 0 Then
852+ Exit Do
853+ Else
854+ depthBody = depthBody - 1
855+ End If
856+ End If
857+ End If
858+ bodyTok.Add Array(types(idx), vals(idx))
859+ idx = idx + 1
860+ Loop
861+ ' consume closing '}'
862+ If idx < n And types(idx) = "PAREN" And vals(idx) = "}" Then idx = idx + 1
863+ Dim bodyStmts As Collection : Set bodyStmts = ParseTokensToAST(bodyTok)
864+ Dim fnode As Map : Set fnode = MakeNode("FuncLiteral" )
865+ fnode.SetValue "params" , params
866+ fnode.SetValue "body" , bodyStmts
867+ Set ParsePrimaryNode = fnode
868+ Exit Function
869+ Else
870+ ' no body found -> emit empty function literal
871+ Dim fnode2 As Map : Set fnode2 = MakeNode("FuncLiteral" )
872+ fnode2.SetValue "params" , params
873+ Dim emptyCol As New Collection
874+ fnode2.SetValue "body" , emptyCol
875+ Set ParsePrimaryNode = fnode2
876+ Exit Function
877+ End If
878+ End If
879+
880+ ' .length special-case on collapsed IDENT token (preserve behavior, but emit Call with callee)
881+ If right$(name, 7 ) = ".length" Then
882+ Dim arrName As String : arrName = left$(name, Len(name) - 7 )
883+ Dim varN As Map : Set varN = MakeNode("Variable" )
884+ varN.SetValue "name" , arrName
885+ Dim lenCall As Map : Set lenCall = MakeNode("Call" )
886+ lenCall.SetValue "callee" , varN
887+ Dim al As New Collection
888+ al.Add varN
889+ lenCall.SetValue "args" , al
831890 idx = idx + 1
891+ Set ParsePrimaryNode = lenCall
832892 Exit Function
833893 End If
834- ' Dotted identifiers: convert into nested Member nodes:
835- ' e.g. "a.b.c" -> Member(Member(Variable("a"), "b"), "c")
836- If InStr(name, "." ) > 0 Then
837- Dim parts() As String
838- parts = Split(name, "." )
839- ' create root variable
840- Dim curNode As Map
841- Dim vNode As New Map
842- vNode.Add "type" , "Variable"
843- vNode.SetValue "name" , parts(0 )
844- Set curNode = vNode
845- Dim pi As Long
846- For pi = LBound(parts) + 1 To UBound(parts)
847- Dim mnode As New Map
848- mnode.Add "type" , "Member"
849- mnode.SetValue "base" , curNode
850- mnode.SetValue "prop" , CStr(parts(pi))
851- Set curNode = mnode
852- Next pi
853- Set ParsePrimaryNode = curNode
894+
895+ ' collapsed index literal, e.g. name[3] in single IDENT token => produce Index node
896+ If InStr(name, "[" ) > 0 Then
897+ Dim base As String : base = left$(name, InStr(name, "[" ) - 1 )
898+ Dim idxStr As String : idxStr = Mid$(name, InStr(name, "[" ) + 1 , Len(name) - InStr(name, "[" ) - 1 )
899+ Dim idxNodeFromStr As Map : Set idxNodeFromStr = ParseExprFromStringToNode(idxStr)
900+ Dim inNode As Map : Set inNode = MakeNode("Index" )
901+ Dim vn As Map : Set vn = MakeNode("Variable" )
902+ vn.SetValue "name" , base
903+ inNode.SetValue "base" , vn
904+ inNode.SetValue "index" , idxNodeFromStr
854905 idx = idx + 1
906+ Set ParsePrimaryNode = inNode
855907 Exit Function
856908 End If
857- ' plain identifier -> Variable node
858- Dim plainVar As Map
859- Set plainVar = MakeNode("Variable" )
860- plainVar.SetValue "name" , name
861- Set ParsePrimaryNode = plainVar
909+
910+ ' create initial variable node for an IDENT and then apply postfix operators:
911+ Dim currentNode As Map : Set currentNode = MakeNode("Variable" )
912+ currentNode.SetValue "name" , name
862913 idx = idx + 1
863- Exit Function
864- If idx + 1 < n Then
865- If types(idx + 1 ) = "PAREN" And vals(idx + 1 ) = "[" Then
866- Dim baseName As String : baseName = name
867- idx = idx + 2 ' after '['
868- Dim indexTokens As New Collection
869- Dim depthParen As Long : depthParen = 0
914+
915+ ' Postfix loop: handle .prop, [...], func calls (...) as postfixes chaining onto currentNode
916+ Do While idx < n
917+ ' member access a.b
918+ If types(idx) = "OP" And vals(idx) = "." Then
919+ idx = idx + 1
920+ If idx < n And types(idx) = "IDENT" Then
921+ Dim mem As Map : Set mem = MakeNode("Member" )
922+ mem.SetValue "base" , currentNode
923+ mem.SetValue "prop" , CStr(vals(idx))
924+ Set currentNode = mem
925+ idx = idx + 1
926+ ' continue loop
927+ Else
928+ ' invalid member access; stop postfixing
929+ Exit Do
930+ End If
931+ ' index access a[expr]
932+ ElseIf types(idx) = "PAREN" And vals(idx) = "[" Then
933+ idx = idx + 1
934+ Dim idxTok As New Collection
935+ Dim depthIdx As Long : depthIdx = 0
870936 Do While idx < n
871937 If types(idx) = "PAREN" Then
872- If vals(idx) = "( " Then
873- depthParen = depthParen + 1
874- End If
875- If vals(idx) = ")" Then
876- depthParen = depthParen - 1
877- End If
878- If vals(idx) = "]" And depthParen = 0 Then
879- Exit Do
938+ If vals(idx) = "[ " Then
939+ depthIdx = depthIdx + 1
940+ ElseIf vals(idx) = "]" Then
941+ If depthIdx = 0 Then
942+ Exit Do
943+ Else
944+ depthIdx = depthIdx - 1
945+ End If
880946 End If
881947 End If
882- indexTokens .Add Array(types(idx), vals(idx))
948+ idxTok .Add Array(types(idx), vals(idx))
883949 idx = idx + 1
884950 Loop
885- If idx >= n Or vals(idx) <> "]" Then
886- err.Raise vbObjectError + 5003 , "Compiler.ParsePrimaryNode" , "Unclosed array index"
887- End If
888- idx = idx + 1 ' After ]
889- Set idxExpr = ParseExprTokensToNode(indexTokens)
890- Dim in2 As Map : Set in2 = MakeNode("Index" )
891- Dim vvar As Map : Set vvar = MakeNode("Variable" )
892- vvar.SetValue "name" , baseName
893- in2.SetValue "base" , vvar
894- in2.SetValue "index" , idxExpr
895- Set ParsePrimaryNode = in2
896- Exit Function
897- End If
898- End If
899- If idx + 1 < n Then
900- If types(idx + 1 ) = "PAREN" And vals(idx + 1 ) = "(" Then
901- idx = idx + 2 ' after '('
951+ Dim idxExprNode As Map : Set idxExprNode = ParseExprTokensToNode(idxTok)
952+ If idx < n And types(idx) = "PAREN" And vals(idx) = "]" Then idx = idx + 1
953+ Dim indexNode As Map : Set indexNode = MakeNode("Index" )
954+ indexNode.SetValue "base" , currentNode
955+ indexNode.SetValue "index" , idxExprNode
956+ Set currentNode = indexNode
957+ ' function / method call: ( arglist )
958+ ElseIf types(idx) = "PAREN" And vals(idx) = "(" Then
959+ ' parse args with nested depth counters (borrowed pattern from previous call parsing logic)
960+ idx = idx + 1
902961 Dim argNodes As New Collection
903- Dim argTokDepthParen As Long , argTokDepthBr As Long , argTokDepthB As Long
904- Do While idx < n
962+ Do
905963 Dim argTok As New Collection
906- argTokDepthParen = 0 : argTokDepthBr = 0 : argTokDepthB = 0
964+ Dim argTokDepthParen As Long : argTokDepthParen = 0
965+ Dim argTokDepthBr As Long : argTokDepthBr = 0
966+ Dim argTokDepthB As Long : argTokDepthB = 0
907967 Do While idx < n
908968 If types(idx) = "PAREN" Then
909- Select Case vals(idx)
969+ Select Case CStr( vals(idx) )
910970 Case "("
911971 argTokDepthParen = argTokDepthParen + 1
912972 Case ")"
913- If argTokDepthParen > 0 Then
914- argTokDepthParen = argTokDepthParen - 1
915- Else
916- Exit Do
917- End If
973+ If argTokDepthParen = 0 Then Exit Do Else argTokDepthParen = argTokDepthParen - 1
918974 Case "["
919975 argTokDepthBr = argTokDepthBr + 1
920976 Case "]"
921- If argTokDepthBr > 0 Then argTokDepthBr = argTokDepthBr - 1
977+ If argTokDepthBr = 0 Then Exit Do Else argTokDepthBr = argTokDepthBr - 1
922978 Case "{"
923979 argTokDepthB = argTokDepthB + 1
924980 Case "}"
925- If argTokDepthB > 0 Then argTokDepthB = argTokDepthB - 1
981+ If argTokDepthB = 0 Then Exit Do Else argTokDepthB = argTokDepthB - 1
926982 End Select
927- End If
928- If argTokDepthParen = 0 And argTokDepthBr = 0 And argTokDepthB = 0 _
929- And types(idx) = "SEP" And (vals(idx) = "," Or vals(idx) = ";" ) Then
930- Exit Do
931- End If
932- If types(idx) = "PAREN" And vals(idx) = ")" And argTokDepthParen = 0 And argTokDepthBr = 0 And argTokDepthB = 0 Then
983+ ElseIf types(idx) = "SEP" And vals(idx) = "," And argTokDepthParen = 0 And argTokDepthBr = 0 And argTokDepthB = 0 Then
933984 Exit Do
934985 End If
935986 argTok.Add Array(types(idx), vals(idx))
@@ -943,29 +994,29 @@ Private Function ParsePrimaryNode(types() As String, vals() As Variant, n As Lon
943994 argNodes.Add litEmpty
944995 End If
945996 If idx < n Then
946- If types(idx) = "SEP" And ( vals(idx) = "," Or vals(idx) = ";" ) Then
997+ If types(idx) = "SEP" And vals(idx) = "," Then
947998 idx = idx + 1
999+ ' continue parsing next arg
9481000 ElseIf types(idx) = "PAREN" And vals(idx) = ")" Then
9491001 idx = idx + 1
9501002 Exit Do
9511003 Else
1004+ ' unexpected token -> stop args parsing
9521005 Exit Do
9531006 End If
9541007 Else
9551008 Exit Do
9561009 End If
9571010 Loop
9581011 Dim callNode As Map : Set callNode = MakeNode("Call" )
959- callNode.SetValue "name " , name
1012+ callNode.SetValue "callee " , currentNode
9601013 callNode.SetValue "args" , argNodes
961- Set ParsePrimaryNode = callNode
962- Exit Function
1014+ Set currentNode = callNode
1015+ Else
1016+ Exit Do
9631017 End If
964- End If
965- Dim varNode As Map : Set varNode = MakeNode("Variable" )
966- varNode.SetValue "name" , name
967- idx = idx + 1
968- Set ParsePrimaryNode = varNode
1018+ Loop
1019+ Set ParsePrimaryNode = currentNode
9691020 Exit Function
9701021 Case "PAREN"
9711022 If v = "(" Then
@@ -2062,3 +2113,5 @@ NormNext:
20622113' End Compiler class
20632114' ---------------------
20642115
2116+
2117+
0 commit comments