diff --git a/_scripts/templates/Cpp/cmake/st.ExternalAntlr4Cpp.cmake b/_scripts/templates/Cpp/cmake/st.ExternalAntlr4Cpp.cmake index b18ed58f0d..d9c7c07646 100644 --- a/_scripts/templates/Cpp/cmake/st.ExternalAntlr4Cpp.cmake +++ b/_scripts/templates/Cpp/cmake/st.ExternalAntlr4Cpp.cmake @@ -5,7 +5,7 @@ include(ExternalProject) #set(ANTLR4_ROOT ${CMAKE_CURRENT_BINARY_DIR}/antlr4_runtime/src/antlr4_runtime) set(ANTLR4_ROOT /antlr4_runtime/src/antlr4_runtime) set(ANTLR4_INCLUDE_DIRS ${ANTLR4_ROOT}/runtime/Cpp/runtime/src) -set(ANTLR4_GIT_REPOSITORY https://github.com/antlr/antlr4.git) +set(ANTLR4_GIT_REPOSITORY https://github.com/kaby76/antlr4.git) if(NOT DEFINED ANTLR4_TAG) # Set to branch name to keep library updated at the cost of needing to rebuild after 'clean' # Set to commit hash to keep the build stable and does not need to rebuild after 'clean' @@ -96,7 +96,7 @@ else() antlr4_runtime PREFIX /antlr4_runtime GIT_REPOSITORY ${ANTLR4_GIT_REPOSITORY} - GIT_TAG df4d68c09cdef73e023b8838a8bc7ca4dff1d1de # ${ANTLR4_TAG} + GIT_TAG f5bd4bec221ca5d916839eca52759720fa28d24c # df4d68c09cdef73e023b8838a8bc7ca4dff1d1de # ${ANTLR4_TAG} DOWNLOAD_DIR ${CMAKE_CURRENT_BINARY_DIR} BUILD_COMMAND "" BUILD_IN_SOURCE 1 diff --git a/golang/Antlr4ng/GoParserBase.ts b/golang/Antlr4ng/GoParserBase.ts index 0a8e1ea4a6..663c71ea43 100644 --- a/golang/Antlr4ng/GoParserBase.ts +++ b/golang/Antlr4ng/GoParserBase.ts @@ -1,26 +1,126 @@ import { Parser, TokenStream, BufferedTokenStream, Token } from 'antlr4ng'; import { GoLexer } from './GoLexer.js'; +import { GoParser, ImportSpecContext } from './GoParser.js'; export default abstract class GoParserBase extends Parser { + + debug: boolean; + table: Set; + constructor(input: TokenStream) { super(input); } + protected myreset(): void { + this.debug = false; + this.table = new Set(); + } + protected closingBracket(): boolean { const stream = this.inputStream as BufferedTokenStream; - const la = stream.LA(1); - return la === GoLexer.R_CURLY || la === GoLexer.R_PAREN || la === Token.EOF; + const la = stream.LT(1); + return la.type === GoParser.R_CURLY || la.type === GoParser.R_PAREN || la.type === Token.EOF; + } + + public isNotReceive(): boolean + { + const stream = this.inputStream as BufferedTokenStream; + const la = stream.LT(2); + return la.type !== GoParser.RECEIVE; + } + + public addImportSpec(): void + { + const ctx = this.context; + const count = ctx.getChildCount(); + if (!(ctx instanceof ImportSpecContext)) { + return; + } + const importSpec = ctx; + var packageName = importSpec.packageName(); + if (packageName != null) + { + var name = packageName.getText(); + if (this.debug) console.log("Entering " + name); + this.table.add(name); + } + else + { + var name = importSpec.importPath().getText(); + name = name.replaceAll("\"", ""); + name = name.replaceAll("\\", "/"); + const pathArr = name.split('/'); + const fileArr = pathArr.at(-1).split('.'); + const fileName = fileArr.at(-1).toString(); + if (this.debug) console.log("Entering " + fileName); + this.table.add(fileName); + } } protected isType(): boolean { const stream = this.inputStream as BufferedTokenStream; const la = stream.LA(1); - return la !== GoLexer.IDENTIFIER; + return la !== GoParser.IDENTIFIER; + } + + public isOperand(): boolean + { + const stream = this.inputStream as BufferedTokenStream; + const la = stream.LT(1); + if (la.text === "err") return true; + var result = true; + if (la.type !== GoParser.IDENTIFIER) { + if (this.debug) console.log("isOperand Returning " + result + " for " + la); + return result; + } + result = this.table.has(la.text); + var la2 = stream.LT(2); + // If it's not followed by a '.', then it really should be + // considered as operand. + if (la2.type !== GoParser.DOT) { + result = true; + if (this.debug) console.log("isOperand Returning " + result + " for " + la); + return result; + } + // If it's followed by '.', and then followed by '(', then + // it is a typeAssertion, and so la must be an operand. + var la3 = stream.LT(3); + if (la3.type === GoParser.L_PAREN) + { + result = true; + if (this.debug) console.log("isOperand Returning " + result + " for " + la); + return result; + } + if (this.debug) console.log("isOperand Returning " + result + " for " + la); + return result; } - protected isNotReceive(): boolean { + public isConversion(): boolean + { const stream = this.inputStream as BufferedTokenStream; - const la = stream.LA(2); - return la !== GoLexer.RECEIVE; - } + const la = stream.LT(1); + var result = la.type !== GoParser.IDENTIFIER; + if (this.debug) console.log("isConversion Returning " + result + " for " + la); + return result; + } + + public isMethodExpr(): boolean + { + const stream = this.inputStream as BufferedTokenStream; + const la = stream.LT(1); + var result = true; + // See if it looks like a method expr. + if (la.type === GoParser.STAR) { + if (this.debug) console.log("isMethodExpr Returning " + result + " for " + la); + return result; + } + if (la.type !== GoParser.IDENTIFIER) { + result = false; + if (this.debug) console.log("isMethodExpr Returning " + result + " for " + la); + return result; + } + result = ! this.table.has(la.text); + if (this.debug) console.log("isMethodExpr Returning " + result + " for " + la); + return result; + } } diff --git a/golang/CSharp/GoParserBase.cs b/golang/CSharp/GoParserBase.cs index 2f0dcefa5a..ecc946c023 100644 --- a/golang/CSharp/GoParserBase.cs +++ b/golang/CSharp/GoParserBase.cs @@ -1,10 +1,14 @@ using System; using System.Collections.Generic; using System.IO; +using System.Linq; using Antlr4.Runtime; public abstract class GoParserBase : Parser { + const bool debug = false; + HashSet table = new HashSet(); + protected GoParserBase(ITokenStream input) : base(input) { @@ -15,30 +19,112 @@ protected GoParserBase(ITokenStream input, TextWriter output, TextWriter errorOu { } + private ITokenStream tokenStream + { + get + { + return TokenStream; + } + } + + protected void myreset() + { + table = new HashSet(); + } protected bool closingBracket() { - int la = tokenStream.LA(1); - return la == GoLexer.R_PAREN || la == GoLexer.R_CURLY || la == Eof; + var la = tokenStream.LT(1); + return la.Type == GoParser.R_PAREN || la.Type == GoParser.R_CURLY || la.Type == Eof; } - private ITokenStream tokenStream + public bool isNotReceive() { - get + var la = tokenStream.LT(2); + return la.Type != GoParser.RECEIVE; + } + + public void addImportSpec() + { + var ctx = this.Context; + var count = ctx.ChildCount; + var importSpec = ctx as GoParser.ImportSpecContext; + if (importSpec == null) return; + var packageName = importSpec.packageName(); + if (packageName != null) { - return TokenStream; + var name = packageName.GetText(); + if (debug) System.Console.WriteLine("Entering " + name); + table.Add(name); + } + else + { + var name = importSpec.importPath().GetText(); + name = name.Replace("\"", ""); + name = name.Replace("\\", "/"); + string[] pathArr = name.Split('/'); + string[] fileArr = pathArr.Last().Split('.'); + string fileName = fileArr.Last().ToString(); + if (debug) System.Console.WriteLine("Entering " + fileName); + table.Add(fileName); } } - public bool isType() + public bool isOperand() { - int la = tokenStream.LA(1); - return la != GoLexer.IDENTIFIER; + var la = tokenStream.LT(1); + if (la.Text == "err") return true; + bool result = true; + if (la.Type != GoParser.IDENTIFIER) { + if (debug) System.Console.WriteLine("isOperand Returning " + result + " for " + la); + return result; + } + result = table.Contains(la.Text); + var la2 = tokenStream.LT(2); + // If it's not followed by a '.', then it really should be + // considered as operand. + if (la2.Type != GoParser.DOT) { + result = true; + if (debug) System.Console.WriteLine("isOperand Returning " + result + " for " + la); + return result; + } + // If it's followed by '.', and then followed by '(', then + // it is a typeAssertion, and so la must be an operand. + var la3 = tokenStream.LT(3); + if (la3.Type == GoParser.L_PAREN) + { + result = true; + if (debug) System.Console.WriteLine("isOperand Returning " + result + " for " + la); + return result; + } + if (debug) System.Console.WriteLine("isOperand Returning " + result + " for " + la); + return result; } - public bool isNotReceive() + public bool isConversion() { - int la = tokenStream.LA(2); - return la != GoLexer.RECEIVE; + var la = tokenStream.LT(1); + var result = la.Type != GoParser.IDENTIFIER; + if (debug) System.Console.WriteLine("isConversion Returning " + result + " for " + la); + return result; + } + + public bool isMethodExpr() + { + var la = tokenStream.LT(1); + bool result = true; + // See if it looks like a method expr. + if (la.Type == GoParser.STAR) { + if (debug) System.Console.WriteLine("isMethodExpr Returning " + result + " for " + la); + return result; + } + if (la.Type != GoParser.IDENTIFIER) { + result = false; + if (debug) System.Console.WriteLine("isMethodExpr Returning " + result + " for " + la); + return result; + } + result = ! table.Contains(la.Text); + if (debug) System.Console.WriteLine("isMethodExpr Returning " + result + " for " + la); + return result; } } diff --git a/golang/Cpp/GoParserBase.cpp b/golang/Cpp/GoParserBase.cpp index b8ca89737e..f66556cb69 100644 --- a/golang/Cpp/GoParserBase.cpp +++ b/golang/Cpp/GoParserBase.cpp @@ -1,24 +1,123 @@ #include "GoParserBase.h" #include "GoParser.h" +void GoParserBase::myreset() +{ + table.clear(); +} + bool GoParserBase::closingBracket() { antlr4::BufferedTokenStream* stream = static_cast(_input); - int la = stream->LA(1); - return la == GoParser::R_CURLY || la == GoParser::R_PAREN || la == antlr4::Token::EOF; + auto la = stream->LT(1); + return la->getType() == GoParser::R_CURLY || la->getType() == GoParser::R_PAREN || la->getType() == antlr4::Token::EOF; } -bool GoParserBase::isType() +bool GoParserBase::isNotReceive() { antlr4::BufferedTokenStream* stream = static_cast(_input); - int la = stream->LA(1); - return la != GoParser::IDENTIFIER; + auto la = stream->LT(2); + return la->getType() != GoParser::RECEIVE; } -bool GoParserBase::isNotReceive() +std::vector split(const std::string& str, char delimiter) +{ + std::vector tokens; + std::stringstream ss(str); + std::string token; + + while (std::getline(ss, token, delimiter)) + { + tokens.push_back(token); + } + + return tokens; +} + +void GoParserBase::addImportSpec() +{ + antlr4::ParserRuleContext* ctx = this->_ctx; + auto count = ctx->children.size(); + auto importSpec = dynamic_cast(ctx); + if (importSpec == nullptr) return; + auto packageName = importSpec->packageName(); + if (packageName != nullptr) + { + auto name = packageName->getText(); + if (debug) std::cout << "Entering " << name; + table.insert(name); + } + else + { + auto name = importSpec->importPath()->getText(); + name.erase(std::remove(name.begin(), name.end(), '\"'), name.end()); + std::replace(name.begin(), name.end(), '\\', '/'); + auto pathArr = split(name, '/'); + auto fileArr = split(pathArr[pathArr.size()-1], '.'); + auto fileName = fileArr[fileArr.size()-1]; + if (this->debug) std::cout << "Entering " << fileName << std::endl; + table.insert(fileName); + } +} + +bool GoParserBase::isOperand() +{ + antlr4::BufferedTokenStream* stream = static_cast(_input); + auto la = stream->LT(1); + if (la->getText() == "err") return true; + bool result = true; + if (la->getType() != GoParser::IDENTIFIER) { + if (debug) std::cout << "isOperand Returning " << result << " for " << la << std::endl; + return result; + } + result = table.find(la->getText()) != table.end(); + auto la2 = stream->LT(2); + // If it's not followed by a '.', then it really should be + // considered as operand. + if (la2->getType() != GoParser::DOT) { + result = true; + if (debug) std::cout << "isOperand Returning " << result << " for " << la << std::endl; + return result; + } + // If it's followed by '.', and then followed by '(', then + // it is a typeAssertion, and so la must be an operand. + auto la3 = stream->LT(3); + if (la3->getType() == GoParser::L_PAREN) + { + result = true; + if (debug) std::cout << "isOperand Returning " << result << " for " << la << std::endl; + return result; + } + if (debug) std::cout << "isOperand Returning " << result << " for " << la << std::endl; + return result; +} + +bool GoParserBase::isConversion() +{ + antlr4::BufferedTokenStream* stream = static_cast(_input); + auto la = stream->LT(1); + auto result = la->getType() != GoParser::IDENTIFIER; + if (debug) std::cout << "isConversion Returning " << result << " for " << la << std::endl; + return result; +} + +bool GoParserBase::isMethodExpr() { antlr4::BufferedTokenStream* stream = static_cast(_input); - int la = stream->LA(2); - return la != GoParser::RECEIVE; + auto la = stream->LT(1); + bool result = true; + // See if it looks like a method expr. + if (la->getType() == GoParser::STAR) { + if (debug) std::cout << "isMethodExpr Returning " << result << " for " << la << std::endl; + return result; + } + if (la->getType() != GoParser::IDENTIFIER) { + result = false; + if (debug) std::cout << "isMethodExpr Returning " << result << " for " << la << std::endl; + return result; + } + result = ! (table.find(la->getText()) != table.end()); + if (debug) std::cout << "isMethodExpr Returning " << result << " for " << la << std::endl; + return result; } diff --git a/golang/Cpp/GoParserBase.h b/golang/Cpp/GoParserBase.h index e487a98764..33e2633919 100644 --- a/golang/Cpp/GoParserBase.h +++ b/golang/Cpp/GoParserBase.h @@ -7,18 +7,20 @@ * should start with lower case char similar to parser rules. */ class GoParserBase : public antlr4::Parser { -public: - GoParserBase(antlr4::TokenStream* input) : Parser(input) { - } +private: + const bool debug = false; + std::set table; +public: + GoParserBase(antlr4::TokenStream* input) : Parser(input) { } virtual ~GoParserBase() {} protected: - /** - * Returns true if the current Token is a closing bracket (")" or "}") - */ + void myreset(); bool closingBracket(); - - bool isType(); bool isNotReceive(); + void addImportSpec(); + bool isOperand(); + bool isConversion(); + bool isMethodExpr(); }; diff --git a/golang/Dart/GoParserBase.dart b/golang/Dart/GoParserBase.dart index abfbbcd792..36ca29fdb0 100644 --- a/golang/Dart/GoParserBase.dart +++ b/golang/Dart/GoParserBase.dart @@ -1,28 +1,122 @@ import 'package:antlr4/antlr4.dart'; -import 'GoLexer.dart'; +import 'GoParser.dart'; +import 'dart:collection'; abstract class GoParserBase extends Parser { - GoParserBase(TokenStream input) - : super(input) + final bool debug = false; + HashSet table = new HashSet(); + + GoParserBase(TokenStream input) : super(input); + + void myreset() { + table = new HashSet(); } bool closingBracket() { - var la = this.tokenStream.LA(1); - return la == GoLexer.TOKEN_R_PAREN || la == GoLexer.TOKEN_R_CURLY || la == IntStream.EOF; + final la = this.tokenStream.LT(1); + return la?.type == GoParser.TOKEN_R_PAREN || la?.type == GoParser.TOKEN_R_CURLY || la?.type == IntStream.EOF; } - bool isType() + bool isNotReceive() { - var la = tokenStream.LA(1); - return la != GoLexer.TOKEN_IDENTIFIER; + final la = tokenStream.LT(2); + return la?.type != GoParser.TOKEN_RECEIVE; } - bool isNotReceive() + void addImportSpec() + { + final ctx = context; + if (ctx == null) return; // Null check for safety + final importSpec = ctx as ImportSpecContext; + if (importSpec == null) return; + final packageName = importSpec.packageName(); + if (packageName != null) { + final name = packageName.text; + if (debug) { + print('Entering $name'); + } + table.add(name); + } else { + var name = importSpec.importPath()?.text; + name = name?.replaceAll('"', ''); + name = name?.replaceAll('\\', '/'); + final pathArr = name?.split('/'); + final fileArr = pathArr?.last.split('.'); + final fileName = fileArr?.last; + if (fileName == null) return; + if (debug) { + print('Entering $fileName'); + } + table.add(fileName); + } + } + + bool isOperand() + { + final la = this.tokenStream.LT(1); + bool result = true; + if (la?.text == "err") { + return true; + } + if (la?.type != GoParser.TOKEN_IDENTIFIER) { + if (debug) { + print('isOperand Returning $result for ${la?.text}'); + } + return result; + } + result = table.contains(la?.text); + final la2 = this.tokenStream.LT(2); + if (la2?.type != GoParser.TOKEN_DOT) { + result = true; + if (debug) { + print('isOperand Returning $result for ${la?.text}'); + } + return result; + } + final la3 = this.tokenStream.LT(3); + if (la3?.type == GoParser.TOKEN_L_PAREN) { + result = true; + if (debug) { + print('isOperand Returning $result for ${la?.text}'); + } + return result; + } + if (debug) { + print('isOperand Returning $result for ${la?.text}'); + } + return result; + } + + bool isConversion() + { + var la = this.tokenStream.LT(1); + return la?.type != GoParser.TOKEN_IDENTIFIER; + } + + bool isMethodExpr() { - var la = tokenStream.LA(1); - return la != GoLexer.TOKEN_RECEIVE; + final la = this.tokenStream.LT(1); + bool result = true; + if (la?.type == GoParser.TOKEN_STAR) { + if (debug) { + print('isMethodExpr Returning $result for ${la?.text}'); + } + return result; + } + if (la?.type != GoParser.TOKEN_IDENTIFIER) { + result = false; + if (debug) { + print('isMethodExpr Returning $result for ${la?.text}'); + } + return result; + } + result = !table.contains(la?.text); + if (debug) { + print('isMethodExpr Returning $result for ${la?.text}'); + } + return result; } } diff --git a/golang/Go/go_parser_base.go b/golang/Go/go_parser_base.go index 7df4c70638..80a531ff29 100644 --- a/golang/Go/go_parser_base.go +++ b/golang/Go/go_parser_base.go @@ -1,30 +1,130 @@ package parser import ( - "github.com/antlr4-go/antlr/v4" + "github.com/antlr4-go/antlr/v4" + "fmt" + "strings" ) // GoParserBase implementation. type GoParserBase struct { - *antlr.BaseParser + *antlr.BaseParser + debug bool + table map[string]bool } +func (p *GoParserBase) myreset() { + p.debug = false + p.table = make(map[string]bool) +} -// Returns true if the current Token is a closing bracket (")" or "}") func (p *GoParserBase) closingBracket() bool { stream := p.GetTokenStream() - la := stream.LA(1) - return la == GoParserR_PAREN || la == GoParserR_CURLY || la == antlr.TokenEOF; + la := stream.LT(1) + return la.GetTokenType() == GoParserR_PAREN || la.GetTokenType() == GoParserR_CURLY || la.GetTokenType() == antlr.TokenEOF; } -func (p *GoParserBase) isType() bool { +func (p *GoParserBase) isNotReceive() bool { stream := p.GetTokenStream() - la := stream.LA(1) - return la != GoParserIDENTIFIER; + la := stream.LT(2) + return la.GetTokenType() != GoParserRECEIVE; } -func (p *GoParserBase) isNotReceive() bool { +func (p *GoParserBase) addImportSpec() { + ctx := p.GetParserRuleContext() + importSpec := ctx.(IImportSpecContext) + if importSpec == nil { + return; + } + packageName := importSpec.PackageName() + if packageName != nil { + name := packageName.GetText() + if p.debug { + fmt.Println("Entering " + name) + p.table[name] = true + } + } else { + name := importSpec.ImportPath().GetText() + name = strings.ReplaceAll(name, "\"", "") + name = strings.ReplaceAll(name, "\\", "/") + pathArr := strings.Split(name, "/") + fileName := pathArr[len(pathArr)-1] + if p.debug { + fmt.Println("Entering " + fileName) + } + p.table[fileName] = true + } +} + +func (p *GoParserBase) isOperand() bool { + stream := p.GetTokenStream() + la := stream.LT(1) + result := true + if la.GetText() == "err" { + return true + } + if la.GetTokenType() != GoParserIDENTIFIER { + if p.debug { + fmt.Println("isOperand Returning ", result, " for ", la) + } + return result + } + result, _ = p.table[la.GetText()] + la2 := stream.LT(2) + if la2.GetTokenType() != GoParserDOT { + result = true + if p.debug { + fmt.Println("isOperand Returning ", result, " for ", la) + } + return result + } + la3 := stream.LT(3) + if la3.GetTokenType() == GoParserL_PAREN { + result = true + if p.debug { + fmt.Println("isOperand Returning ", result, " for ", la) + } + return result + } + if p.debug { + fmt.Println("isOperand Returning ", result, " for ", la) + } + return result +} + +func (p *GoParserBase) isConversion() bool { + stream := p.GetTokenStream() + la := stream.LT(1) + result := la.GetTokenType() != GoParserIDENTIFIER; + if p.debug { + fmt.Println("isConversion Returning ", result, " for ", la) + } + return result +} + +func (p *GoParserBase) isMethodExpr() bool { stream := p.GetTokenStream() - la := stream.LA(2) - return la != GoParserRECEIVE; + la := stream.LT(1) + result := true + if la.GetTokenType() == GoParserSTAR { + if p.debug { + fmt.Println("isMethodExpr Returning ", result, " for ", la) + } + return result + } + if la.GetTokenType() != GoParserIDENTIFIER { + result = false + if p.debug { + fmt.Println("isMethodExpr Returning ", result, " for ", la) + } + return result + } + _, found := p.table[la.GetText()] + if ! found { + result = true + } + if p.debug { + fmt.Println("isMethodExpr Returning ", result, " for ", la) + } + return result } diff --git a/golang/GoParser.g4 b/golang/GoParser.g4 index d59b6d4a10..c1f0773a25 100644 --- a/golang/GoParser.g4 +++ b/golang/GoParser.g4 @@ -44,7 +44,7 @@ sourceFile ; packageClause - : PACKAGE packageName + : PACKAGE packageName {this.myreset();} ; packageName @@ -58,7 +58,7 @@ importDecl ; importSpec - : (DOT | packageName)? importPath + : (DOT | packageName)? importPath {this.addImportSpec();} ; importPath @@ -229,7 +229,7 @@ deferStmt ; ifStmt - : IF (expression | eos expression | simpleStmt eos expression) block (ELSE (ifStmt | block))? + : IF (expression | (SEMI | EOS) expression | simpleStmt (SEMI | EOS) expression) block (ELSE (ifStmt | block))? ; switchStmt @@ -410,11 +410,11 @@ expression | expression LOGICAL_OR expression ; -primaryExpr - : operand - | { this.isType() }? conversion - | methodExpr - | primaryExpr ( DOT IDENTIFIER | index | slice_ | typeAssertion | arguments) +primaryExpr : + ( {this.isOperand()}? operand + | {this.isConversion()}? conversion + | {this.isMethodExpr()}? methodExpr ) + ( DOT IDENTIFIER | index | slice_ | typeAssertion | arguments )* ; conversion diff --git a/golang/Java/GoParserBase.java b/golang/Java/GoParserBase.java index 0146f26563..e19c9af449 100644 --- a/golang/Java/GoParserBase.java +++ b/golang/Java/GoParserBase.java @@ -1,5 +1,8 @@ import java.util.List; import org.antlr.v4.runtime.*; +import java.io.PrintStream; +import java.util.HashSet; +import java.util.Set; /** * All parser methods that used in grammar (p, prev, notLineTerminator, etc.) @@ -7,10 +10,17 @@ */ public abstract class GoParserBase extends Parser { + private static final boolean debug = false; + private Set table = new HashSet<>(); + protected GoParserBase(TokenStream input) { super(input); } + protected void myreset() + { + table = new HashSet(); + } /** * Returns true if the current Token is a closing bracket (")" or "}") @@ -18,21 +28,101 @@ protected GoParserBase(TokenStream input) { protected boolean closingBracket() { BufferedTokenStream stream = (BufferedTokenStream)_input; - int la = stream.LA(1); - return la == GoLexer.R_PAREN || la == GoLexer.R_CURLY || la == Token.EOF; + var la = stream.LT(1); + return la.getType() == GoLexer.R_PAREN || la.getType() == GoLexer.R_CURLY || la.getType() == Token.EOF; } - protected boolean isType() + + protected boolean isNotReceive() { BufferedTokenStream stream = (BufferedTokenStream)_input; - int la = stream.LA(1); - return la != GoLexer.IDENTIFIER; + var la = stream.LT(2); + return la.getType() != GoLexer.RECEIVE; } - protected boolean isNotReceive() + public void addImportSpec() { + if (!(this._ctx instanceof GoParser.ImportSpecContext)) { + return; + } + GoParser.ImportSpecContext importSpec = (GoParser.ImportSpecContext) this._ctx; + if (importSpec == null) { + return; + } + GoParser.PackageNameContext packageName = importSpec.packageName(); + if (packageName != null) { + String name = packageName.getText(); + if (debug) System.out.println("Entering " + name); + table.add(name); + } else { + String name = importSpec.importPath().getText(); + name = name.replace("\"", ""); + name = name.replace("\\", "/"); + String[] pathArr = name.split("/"); + String[] fileArr = pathArr[pathArr.length - 1].split("\\."); + String fileName = fileArr[fileArr.length - 1]; + if (debug) System.out.println("Entering " + fileName); + table.add(fileName); + } + } + + public boolean isOperand() { + BufferedTokenStream stream = (BufferedTokenStream)_input; + var la = stream.LT(1); + if ("err".equals(la.getText())) { + return true; + } + boolean result = true; + if (la.getType() != GoParser.IDENTIFIER) { + if (debug) System.out.println("isOperand Returning " + result + " for " + la); + return result; + } + result = table.contains(la.getText()); + Token la2 = stream.LT(2); + if (la2.getType() != GoParser.DOT) { + result = true; + if (debug) System.out.println("isOperand Returning " + result + " for " + la); + return result; + } + Token la3 = stream.LT(3); + if (la3.getType() == GoParser.L_PAREN) { + result = true; + if (debug) System.out.println("isOperand Returning " + result + " for " + la); + return result; + } + if (debug) System.out.println("isOperand Returning " + result + " for " + la); + return result; + } + + public boolean isMethodExpr() { + BufferedTokenStream stream = (BufferedTokenStream)_input; + Token la = stream.LT(1); + boolean result = true; + + // If '*' => definitely a method expression + if (la.getType() == GoParser.STAR) { + if (debug) System.out.println("isMethodExpr Returning " + result + " for " + la); + return result; + } + + // If not an identifier, can't be a method expr + if (la.getType() != GoParser.IDENTIFIER) { + result = false; + if (debug) System.out.println("isMethodExpr Returning " + result + " for " + la); + return result; + } + + // If it's an identifier not in the table => method expr + result = !table.contains(la.getText()); + if (debug) System.out.println("isMethodExpr Returning " + result + " for " + la); + return result; + } + + protected boolean isConversion() { BufferedTokenStream stream = (BufferedTokenStream)_input; - int la = stream.LA(2); - return la != GoLexer.RECEIVE; + var la = stream.LT(1); + var result = la.getType() != GoLexer.IDENTIFIER; + if (debug) System.out.println("isConversion Returning " + result + " for " + la); + return result; } } diff --git a/golang/Python3/GoParserBase.py b/golang/Python3/GoParserBase.py index c64ae5c042..1b5a8ae3e8 100644 --- a/golang/Python3/GoParserBase.py +++ b/golang/Python3/GoParserBase.py @@ -1,15 +1,96 @@ +import sys from antlr4 import * +if sys.version_info[1] > 5: + from typing import TextIO +else: + from typing.io import TextIO class GoParserBase(Parser): - def closingBracket(self) -> bool: - la = self._input.LA(1) - return la == self.R_PAREN or la == self.R_CURLY or la == Token.EOF + debug = False + + def __init__(self, input:TokenStream, output:TextIO = sys.stdout): + super().__init__(input, output) + self.table = set() - def isType(self) -> bool: - la = self._input.LA(1) - return la != self.IDENTIFIER + def myreset(self): + la = 1 + + def closingBracket(self) -> bool: + la = self._input.LT(1) + return la.type == self.R_PAREN or la.type == self.R_CURLY or la.type == Token.EOF def isNotReceive(self) -> bool: - la = self._input.LA(2) - return la != self.RECEIVE + la = self._input.LT(2) + return la.type != self.RECEIVE + + def addImportSpec(self): + ctx = self._ctx + if not isinstance(ctx, self.ImportSpecContext): + return + importSpec = ctx + if importSpec.packageName() is not None: + name = importSpec.packageName().getText() + if self.debug: + print("Entering", name) + self.table.add(name) + else: + name = importSpec.importPath().getText() + name = name.replace("\"", "") + name = name.replace("\\", "/") + path_arr = name.split('/') + file_arr = path_arr[-1].split('.') + file_name = file_arr[-1] + if self.debug: + print("Entering", file_name) + self.table.add(file_name) + + def isOperand(self) -> bool: + la = self._input.LT(1) + if la.text == "err": + return True + result = True + if la.type != self.IDENTIFIER: + if self.debug: + print(f"isOperand Returning {result} for {la.text}") + return result + result = (la.text in self.table) + la2 = self._input.LT(2) + if la2.type != self.DOT: + result = True + if self.debug: + print(f"isOperand Returning {result} for {la.text}") + return result + la3 = self._input.LT(3) + if la3.type == self.L_PAREN: + result = True + if self.debug: + print(f"isOperand Returning {result} for {la.text}") + return result + if self.debug: + print(f"isOperand Returning {result} for {la.text}") + return result + + def isConversion(self) -> bool: + la = self._input.LT(1) + result = (la.type != self.IDENTIFIER) + if self.debug: + print(f"isConversion Returning {result} for {la.text}") + return result + + def isMethodExpr(self) -> bool: + la = self._input.LT(1) + result = True + if la.type == self.STAR: + if self.debug: + print(f"isMethodExpr Returning {result} for {la.text}") + return result + if la.type != self.IDENTIFIER: + result = False + if self.debug: + print(f"isMethodExpr Returning {result} for {la.text}") + return result + result = (la.text not in self.table) + if self.debug: + print(f"isMethodExpr Returning {result} for {la.text}") + return result diff --git a/golang/TypeScript/GoParserBase.ts b/golang/TypeScript/GoParserBase.ts index 03ca80cb06..74adb082c0 100644 --- a/golang/TypeScript/GoParserBase.ts +++ b/golang/TypeScript/GoParserBase.ts @@ -1,26 +1,119 @@ import { Parser, TokenStream, BufferedTokenStream, Token } from 'antlr4'; -import GoLexer from './GoLexer'; +import GoLexer from './GoLexer.js'; +import GoParser, { ImportSpecContext } from './GoParser.js'; export default abstract class GoParserBase extends Parser { + + debug: boolean; + table: Set; + constructor(input: TokenStream) { super(input); } + protected myreset(): void { + this.debug = false; + this.table = new Set(); + } + protected closingBracket(): boolean { const stream = this._input as BufferedTokenStream; - const la = stream.LA(1); - return la === GoLexer.R_CURLY || la === GoLexer.R_PAREN || la === Token.EOF; + const la = stream.LT(1); + return la.type === GoParser.R_CURLY || la.type === GoParser.R_PAREN || la.type === Token.EOF; + } + + public isNotReceive(): boolean { + const stream = this._input as BufferedTokenStream; + const la = stream.LT(2); + return la.type !== GoParser.RECEIVE; + } + + public addImportSpec(): void { + const ctx = this._ctx; + const count = ctx.getChildCount(); + if (!(ctx instanceof ImportSpecContext)) { + return; + } + const importSpec = ctx; + var packageName = importSpec.packageName(); + if (packageName != null) { + var name = packageName.getText(); + if (this.debug) console.log("Entering " + name); + this.table.add(name); + } + else { + var name = importSpec.importPath().getText(); + name = name.replace("\"", ""); + name = name.replace("\"", ""); + name = name.replace("\\", "/"); + const pathArr = name.split('/'); + const fileArr = pathArr.at(-1).split('.'); + const fileName = fileArr.at(-1).toString(); + if (this.debug) console.log("Entering " + fileName); + this.table.add(fileName); + } } protected isType(): boolean { const stream = this._input as BufferedTokenStream; const la = stream.LA(1); - return la !== GoLexer.IDENTIFIER; + return la !== GoParser.IDENTIFIER; + } + + public isOperand(): boolean { + const stream = this._input as BufferedTokenStream; + const la = stream.LT(1); + if (la.text === "err") return true; + var result = true; + if (la.type !== GoParser.IDENTIFIER) { + if (this.debug) console.log("isOperand Returning " + result + " for " + la); + return result; + } + result = this.table.has(la.text); + var la2 = stream.LT(2); + // If it's not followed by a '.', then it really should be + // considered as operand. + if (la2.type !== GoParser.DOT) { + result = true; + if (this.debug) console.log("isOperand Returning " + result + " for " + la); + return result; + } + // If it's followed by '.', and then followed by '(', then + // it is a typeAssertion, and so la must be an operand. + var la3 = stream.LT(3); + if (la3.type === GoParser.L_PAREN) { + result = true; + if (this.debug) console.log("isOperand Returning " + result + " for " + la); + return result; + } + if (this.debug) console.log("isOperand Returning " + result + " for " + la); + return result; } - protected isNotReceive(): boolean { + public isConversion(): boolean { const stream = this._input as BufferedTokenStream; - const la = stream.LA(2); - return la !== GoLexer.RECEIVE; - } + const la = stream.LT(1); + var result = la.type !== GoParser.IDENTIFIER; + if (this.debug) console.log("isConversion Returning " + result + " for " + la); + return result; + } + + public isMethodExpr(): boolean { + const stream = this._input as BufferedTokenStream; + const la = stream.LT(1); + var result = true; + // See if it looks like a method expr. + if (la.type === GoParser.STAR) { + if (this.debug) console.log("isMethodExpr Returning " + result + " for " + la); + return result; + } + if (la.type !== GoParser.IDENTIFIER) { + result = false; + if (this.debug) console.log("isMethodExpr Returning " + result + " for " + la); + return result; + } + result = !this.table.has(la.text); + if (this.debug) console.log("isMethodExpr Returning " + result + " for " + la); + return result; + } }