"{ Package: 'jv:tea/compiler' }"
"{ NameSpace: Smalltalk }"
RBParser subclass:#TParser
instanceVariableNames:'parsingInlineAssembly'
classVariableNames:''
poolDictionaries:''
category:'Languages-Tea-Compiler-AST'
!
!TParser class methodsFor:'parsing'!
parseMethod: aString
^ self parseMethod: aString onError: [:msg :pos | self error: msg , ' at ', pos printString ]
"Created: / 20-08-2015 / 17:04:49 / Jan Vrany <jan.vrany@fit.cvut.cz>"
! !
!TParser methodsFor:'accessing'!
initializeParserWith: aString type: aSymbol
|stream|
stream := ReadStream on: aString.
source := aString.
self scanner: (TScanner
perform: aSymbol
with: stream
with: self errorBlock)
"Created: / 02-09-2015 / 05:57:33 / Jan Vrany <jan.vrany@fit.cvut.cz>"
! !
!TParser methodsFor:'initialization & release'!
scanner: aScanner
parsingInlineAssembly := false.
super scanner: aScanner.
"Created: / 02-09-2015 / 06:34:01 / Jan Vrany <jan.vrany@fit.cvut.cz>"
! !
!TParser methodsFor:'private-parsing'!
parseArgOrLocal
"Parse either method/block argument or a local (inside | | )"
| variable |
variable := self parseVariableNode.
variable typeSpec: (self parseTypeSpec: false).
^ variable
"Created: / 20-08-2015 / 16:57:55 / Jan Vrany <jan.vrany@fit.cvut.cz>"
"Modified: / 21-08-2015 / 21:20:13 / Jan Vrany <jan.vrany@fit.cvut.cz>"
!
parseBinaryPattern
| method |
method := super parseBinaryPattern.
method returnTypeSpec: (self parseTypeSpec: true).
^ method
"Created: / 21-08-2015 / 22:55:43 / Jan Vrany <jan.vrany@fit.cvut.cz>"
!
parseInlineAssembly
| position blockNode firstLine prevScope|
position := currentToken start.
firstLine := currentToken lineNumber.
parsingInlineAssembly := true.
self step. "/ To eat %[ token
blockNode := self parseBlockArgsInto: TInlineAssemblyNode new.
"/ node arguments do:[:eachArg | eachArg parent:self].
blockNode left: position.
blockNode firstLineNumber:firstLine.
prevScope := currentScope.
currentScope := blockNode.
self rememberLastNode:blockNode.
blockNode body: (self parseStatements: false).
RBParser isSmalltalkX ifTrue:[
self addComments:(scanner getCommentsBeforeToken) afterNode:blockNode body.
].
"/ ensure that right is set, even if parse aborted due to an error
blockNode right: currentToken start-1.
(currentToken isTInlineAssemblyEnd )
ifFalse: [self parserError: '''$]'' expected'].
"/ fix right
blockNode right: currentToken start.
blockNode lastLineNumber:currentToken lineNumber.
parsingInlineAssembly := false.
self step.
self addComments:(scanner getCommentsBeforeToken) afterNode:blockNode.
currentScope := prevScope.
^ blockNode
"Created: / 02-09-2015 / 06:25:54 / Jan Vrany <jan.vrany@fit.cvut.cz>"
!
parseKeywordPattern
| method |
method := super parseKeywordPattern.
method returnTypeSpec: (self parseTypeSpec: true).
^ method
"Created: / 20-08-2015 / 17:33:09 / Jan Vrany <jan.vrany@fit.cvut.cz>"
"Modified: / 21-08-2015 / 22:50:23 / Jan Vrany <jan.vrany@fit.cvut.cz>"
!
parseStatementList: tagBoolean into: sequenceNode
| statements return periods returnPosition returnLineNumber node valueNode|
return := false.
statements := OrderedCollection new.
periods := OrderedCollection new.
self addComments:(scanner getCommentsBeforeToken) beforeNode:sequenceNode.
tagBoolean ifTrue: [self parseResourceTag].
[
"skip empty statements"
emptyStatements ifTrue:
[[currentToken isSpecial and: [currentToken value == $.]] whileTrue:
[periods add: currentToken start.
self step]].
self atEnd
or: [(currentToken isSpecial and: ['])}' includes: currentToken value ])
or: [(currentToken isTInlineAssemblyEnd)]]
] whileFalse:[
self addComments:(scanner getCommentsBeforeToken) beforeNode:node "value".
return ifTrue: [
self class isSmalltalkX
ifTrue:
["could output a warning"]
ifFalse:
[self
parserError: 'End of statement list encounted (statements after return)'
lastNode:node]].
(currentToken isTInlineAssemblyBegin) ifTrue:[
node := self parseInlineAssembly.
statements add: node.
] ifFalse:[
(currentToken isSTXPrimitiveCode)
ifTrue:[
" primPosition := currentToken start. "
node := RBSTXPrimitiveCCodeNode new codeToken: currentToken.
self addComments:(scanner getCommentsBeforeToken) afterNode:node.
statements add: node.
self step.
] ifFalse:[
(currentToken isSpecial and: [currentToken value == $^])
ifTrue:
[
returnPosition := currentToken start.
returnLineNumber := currentToken lineNumber.
self step.
valueNode := self parseAssignment.
node := RBReturnNode return: returnPosition value: valueNode.
node lineNumber:returnLineNumber.
scanner atEnd ifFalse:[
self addComments:(scanner getCommentsBeforeToken) afterNode:node value.
].
statements add: node.
return := true]
ifFalse:
[
node := self parseAssignment.
node notNil ifTrue:[
self addComments:(scanner getCommentsAfterTokenIfInLine:node lastLineNumber) afterNode:node.
scanner atEnd ifFalse:[
self addComments:(scanner getCommentsAfterToken) afterNode:node.
self addComments:(scanner getCommentsBeforeToken) afterNode:node.
].
statements add: node
]].
].
].
(currentToken isSpecial and: [currentToken value == $.])
ifTrue:
[periods add: currentToken start.
self step]
ifFalse:
[return := true].
emptyStatements
ifTrue:
[[currentToken isSpecial and: [currentToken value == $.]] whileTrue:
[periods add: currentToken start.
self step]]].
sequenceNode
statements: statements;
periods: periods.
self addComments:(scanner getCommentsBeforeToken) afterNode:node "value".
^sequenceNode
"Created: / 02-09-2015 / 06:23:44 / Jan Vrany <jan.vrany@fit.cvut.cz>"
!
parseType
"
type ::= type_simple ( '|' type )*
"
| types |
types := OrderedCollection with: self parseTypeSimple.
[ currentToken isBinary and:[ currentToken value == #| ] ] whileTrue:[
self step. "/ eat bar.
types add: self parseTypeSimple.
].
^ types size == 1 ifTrue:[ types anElement ] ifFalse:[ TUnionTypeNode new types: types ]
"Created: / 20-08-2015 / 17:18:11 / Jan Vrany <jan.vrany@fit.cvut.cz>"
"Modified: / 21-08-2015 / 21:12:33 / Jan Vrany <jan.vrany@fit.cvut.cz>"
!
parseTypeSimple
"
type_simple::= identifier ('[' type_parameters ']')?
"
| type |
currentToken isIdentifier ifTrue:[
type := TSimpleTypeNode new.
type name: currentToken value.
] ifFalse:[
(currentToken isLiteral and:[ currentToken value isNil ]) ifFalse:[
self parserError: 'type identifier expected'.
].
type := TSimpleTypeNode new.
type name: 'nil'.
].
type
start: currentToken start;
stop: currentToken stop;
lineNumber: currentToken lineNumber.
self step. "/ eat identifier.
^ type
"Created: / 20-08-2015 / 17:20:16 / Jan Vrany <jan.vrany@fit.cvut.cz>"
"Modified: / 21-08-2015 / 21:13:01 / Jan Vrany <jan.vrany@fit.cvut.cz>"
!
parseTypeSpec: forReturn
parsingInlineAssembly ifTrue:[ ^ nil ].
(currentToken isBinary and: [currentToken value == #<]) ifTrue: [
| start stop type |
start := currentToken start.
self step.
forReturn ifTrue:[
(currentToken isSpecial and:[ currentToken value == $^ ]) ifFalse:[
self parserError: '''^'' expected'.
].
self step.
].
type := self parseType.
(currentToken isBinary and: [currentToken value == #>])
ifFalse: [self parserError: '''>'' expected'].
stop := currentToken stop.
self step.
^ TTypeSpecNode new
type: type;
start: start;
stop: stop.
] ifFalse:[
self parserError: 'type annotation expected'
].
"Created: / 20-08-2015 / 17:13:10 / Jan Vrany <jan.vrany@fit.cvut.cz>"
"Modified: / 02-09-2015 / 07:01:45 / Jan Vrany <jan.vrany@fit.cvut.cz>"
!
parseUnaryPattern
| method |
method := super parseUnaryPattern.
method returnTypeSpec: (self parseTypeSpec: true).
^ method
"Created: / 21-08-2015 / 22:54:11 / Jan Vrany <jan.vrany@fit.cvut.cz>"
! !