diff --git a/client/package.json b/client/package.json index d51460a..d48998d 100644 --- a/client/package.json +++ b/client/package.json @@ -3,7 +3,7 @@ "description": "A language server for Verilog", "author": "chrehall68", "license": "MIT", - "version": "1.0.2", + "version": "1.0.3", "repository": { "type": "git", "url": "https://github.com/chrehall68/vls" diff --git a/client/src/extension.ts b/client/src/extension.ts index 8a79a67..7b73a01 100644 --- a/client/src/extension.ts +++ b/client/src/extension.ts @@ -30,7 +30,7 @@ async function downloadToBin( } async function resolveServerExecutable(ctx: ExtensionContext): Promise { - const version = "1.0.2"; + const version = "1.0.3"; const platformDetails = { win32: { url: `https://github.com/chrehall68/vls/releases/download/${version}/vls-windows-amd64.exe`, diff --git a/server/internal/lang/parser.go b/server/internal/lang/parser.go index 0e02300..b51dba1 100644 --- a/server/internal/lang/parser.go +++ b/server/internal/lang/parser.go @@ -785,13 +785,27 @@ func (p *Parser) parseAssignmentNode(tokens []Token, pos int) (result Assignment } func (p *Parser) parseTypeNode(tokens []Token, pos int) (result TypeNode, newPos int, err error) { - // TYPE [] - pos, err = p.checkToken("type", []string{"type"}, pos, tokens) + // (TYPE | DIRECTION [TYPE]) [] + pos, err = p.checkToken("type", []string{"type", "direction"}, pos, tokens) if err != nil { return } - result.Type = tokens[pos] - pos++ + + if tokens[pos].Type == "direction" { + // potentially take a type + potentialPos, e := p.checkToken("type", []string{"type"}, pos+1, tokens) + if e == nil { + // success! + result.Type = tokens[potentialPos] + pos = potentialPos + 1 + } else { + result.Type = tokens[pos] + pos++ + } + } else { + result.Type = tokens[pos] + pos++ + } // now try taking the range; it's ok if it fails since it's optional rangeNode, potentialPos, e := p.parseRangeNode(tokens, pos) @@ -900,14 +914,27 @@ func (p *Parser) parseDeclarationNode(tokens []Token, pos int) (result Declarati } func (p *Parser) parseBeginBlock(tokens []Token, pos int) (result BeginBlockNode, newPos int, err error) { - // BEGIN END + // BEGIN [ COLON ] { } END pos, err = p.checkToken("begin block", []string{"begin"}, pos, tokens) if err != nil { return } pos++ - // get the generateable statements + // optionally, get colon + potentialPos, e := p.checkToken("begin block", []string{"colon"}, pos, tokens) + if e == nil { + pos = potentialPos + 1 + + // get identifier + pos, err = p.checkToken("begin block", []string{"identifier"}, pos, tokens) + if err != nil { + return + } + pos++ + } + + // get the alwaysable statements generateableStatements, potentialPos, e := p.parseAlwaysStatements(tokens, pos) if e != nil { err = e @@ -1824,6 +1851,9 @@ func getInteriorStatementsFromAlwaysStatement(statement AlwaysStatement) []Inter result = append(result, getInteriorStatementsFromAlwaysStatement(statement.ForBlock.Body)...) } else if statement.IfBlock != nil { result = append(result, getInteriorStatementsFromAlwaysStatement(statement.IfBlock.Body)...) + if statement.IfBlock.Else != nil { + result = append(result, getInteriorStatementsFromAlwaysStatement(*statement.IfBlock.Else)...) + } } else if statement.InteriorNode != nil { result = append(result, getInteriorStatementsFromInteriorNode(*statement.InteriorNode)...) } @@ -1882,6 +1912,9 @@ func getFunctionStatementsFromAlwaysStatement(statement AlwaysStatement) []Funct result = append(result, *statement.FunctionNode) } else if statement.IfBlock != nil { result = append(result, getFunctionStatementsFromAlwaysStatement(statement.IfBlock.Body)...) + if statement.IfBlock.Else != nil { + result = append(result, getFunctionStatementsFromAlwaysStatement(*statement.IfBlock.Else)...) + } } else if statement.InteriorNode != nil { result = append(result, getFunctionStatementsFromInteriorNode(*statement.InteriorNode)...) } @@ -1949,7 +1982,7 @@ Grammar: -> EQUAL { COMMA EQUAL } SEMICOLON | { COMMA } SEMICOLON - -> TYPE [] + -> (TYPE | DIRECTION [TYPE]) [] -> LBRACKET RBRACKET | LBRACKET RBRACKET -> LBRACKET COLON RBRACKET -> LITERAL | DEFINE @@ -1967,7 +2000,7 @@ Grammar: -> DEFPARAM { DOT } EQUAL SEMICOLON -> GENERATE { } ENDGENERATE - -> BEGIN { } END + -> BEGIN [ COLON ] { } END -> FOR LPAREN [] SEMICOLON [] SEMICOLON [] RPAREN -> IF LPAREN RPAREN [ELSE ] -> DOLLAR [LPAREN { COMMA } RPAREN] SEMICOLON diff --git a/server/internal/lang/vlexer.go b/server/internal/lang/vlexer.go index 64d8242..430e105 100644 --- a/server/internal/lang/vlexer.go +++ b/server/internal/lang/vlexer.go @@ -68,7 +68,8 @@ func NewVLexer(logger *zap.Logger) *VLexer { vlexer.AddMappingNoCapture(regexp.MustCompile(`^((\$time)|(\$realtime))`), "funcliteral") vlexer.AddMappingNoCapture(regexp.MustCompile(`^((\$signed)|(\$unsigned))`), "signed") // variable-related - vlexer.AddMappingNoCapture(regexp.MustCompile(`^((reg)|(wire)|(genvar)|(parameter)|(input)|(output)|(inout)|(integer))`), "type") + vlexer.AddMappingNoCapture(regexp.MustCompile(`^((reg)|(wire)|(genvar)|(parameter)|(integer))`), "type") + vlexer.AddMappingNoCapture(regexp.MustCompile(`^((input)|(output)|(inout))`), "direction") vlexer.AddMappingNoCapture(regexp.MustCompile(`^defparam`), "defparam") vlexer.AddMapping(regexp.MustCompile("^`?[A-Za-z][a-zA-Z0-9_]*"), func(code string) (Token, error) { re := regexp.MustCompile("^`?(?P[A-Za-z][a-zA-Z0-9_]*)") diff --git a/server/internal/vlsp/semtokens.go b/server/internal/vlsp/semtokens.go index 911d4f1..6234d8a 100644 --- a/server/internal/vlsp/semtokens.go +++ b/server/internal/vlsp/semtokens.go @@ -56,6 +56,7 @@ func Encode(tokens []lang.Token) []uint32 { tokenTypeToInt := map[string]uint32{ "comment": 1, "type": 0, + "direction": 0, "defparam": 0, "literal": 2, "module": 3,