diff --git a/Units/parser-genie.r/simple.genie.b/args.ctags b/Units/parser-genie.r/simple.genie.b/args.ctags new file mode 100644 index 0000000000..3bba6778c9 --- /dev/null +++ b/Units/parser-genie.r/simple.genie.b/args.ctags @@ -0,0 +1,2 @@ +--sort=no +--fields=+neKl diff --git a/Units/parser-genie.r/simple.genie.b/expected.tags b/Units/parser-genie.r/simple.genie.b/expected.tags new file mode 100644 index 0000000000..ab049f81b4 --- /dev/null +++ b/Units/parser-genie.r/simple.genie.b/expected.tags @@ -0,0 +1 @@ +main input.gs 1;" method line:1 language:Genie diff --git a/Units/parser-genie.r/simple.genie.b/input.gs b/Units/parser-genie.r/simple.genie.b/input.gs new file mode 100644 index 0000000000..a758ec928b --- /dev/null +++ b/Units/parser-genie.r/simple.genie.b/input.gs @@ -0,0 +1,2 @@ +init + print "Hello World" diff --git a/Units/parser-vala.r/class.vala.d/args.ctags b/Units/parser-vala.r/class.vala.d/args.ctags new file mode 100644 index 0000000000..3bba6778c9 --- /dev/null +++ b/Units/parser-vala.r/class.vala.d/args.ctags @@ -0,0 +1,2 @@ +--sort=no +--fields=+neKl diff --git a/Units/parser-vala.r/class.vala.d/expected.tags b/Units/parser-vala.r/class.vala.d/expected.tags new file mode 100644 index 0000000000..3da11114d4 --- /dev/null +++ b/Units/parser-vala.r/class.vala.d/expected.tags @@ -0,0 +1,10 @@ +main input.vala /^void main(string[] args) {$/;" method line:8 language:Vala +Address input.vala /^class Address {$/;" class line:15 language:Vala +country input.vala /^ string country;$/;" field line:16 language:Vala class:Address typeref:typename:string +city input.vala /^ string city;$/;" field line:17 language:Vala class:Address typeref:typename:string +street input.vala /^ string street;$/;" field line:18 language:Vala class:Address typeref:typename:string +building input.vala /^ int building;$/;" field line:19 language:Vala class:Address typeref:typename:int +floor input.vala /^ int floor;$/;" field line:20 language:Vala class:Address typeref:typename:int +Person input.vala /^class Person {$/;" class line:23 language:Vala +address input.vala /^ public Address address {get; set;}$/;" property line:24 language:Vala class:Person typeref:unknown:Address +name input.vala /^ public string name {get; set;}$/;" property line:25 language:Vala class:Person typeref:typename:string diff --git a/Units/parser-vala.r/class.vala.d/input.vala b/Units/parser-vala.r/class.vala.d/input.vala new file mode 100644 index 0000000000..e9ff415f91 --- /dev/null +++ b/Units/parser-vala.r/class.vala.d/input.vala @@ -0,0 +1,38 @@ +/* + * vala HelloWorld + * + * $ valac input.vala + * $ ./input + * Hello John, you're 21 years old + */ +void main(string[] args) { + var p = new Person(); + p.name = "John"; + p.age = 21; + print("Hello %s, you're %d years old\n", p.name, p.age); +} + +class Address { + string country; + string city; + string street; + int building; + int floor; +} + +class Person { + public Address address {get; set;} + public string name {get; set;} + private int d_age; + + public int age { + get { return d_age;} + set { + if (value > 0) { + d_age = value; + } else { + d_age = 0; + } + } + } +} diff --git a/Units/parser-vala.r/comments.vala.d/args.ctags b/Units/parser-vala.r/comments.vala.d/args.ctags new file mode 100644 index 0000000000..3bba6778c9 --- /dev/null +++ b/Units/parser-vala.r/comments.vala.d/args.ctags @@ -0,0 +1,2 @@ +--sort=no +--fields=+neKl diff --git a/Units/parser-vala.r/comments.vala.d/expected.tags b/Units/parser-vala.r/comments.vala.d/expected.tags new file mode 100644 index 0000000000..55e8edace3 --- /dev/null +++ b/Units/parser-vala.r/comments.vala.d/expected.tags @@ -0,0 +1,6 @@ +f1 input.vala /^void f1 () {$/;" method line:1 language:Vala +f2 input.vala /^void f2 () {print ("hello");} \/\/ void g3 () { print ("hello");}$/;" method line:7 language:Vala +f3 input.vala /^void f3 () {print ("hello");} void g4 () { print ("hello");}$/;" method line:8 language:Vala +g4 input.vala /^void f3 () {print ("hello");} void g4 () { print ("hello");}$/;" method line:8 language:Vala +f4 input.vala /^void f4 () {print ("hello"); \/\/ void g5 () { print ("hello");}$/;" method line:9 language:Vala +g7 input.vala /^} void g7 () { print ("hello");} \/\/ void g8 () {} ; void f5 () { print ("hello");} # void g/;" method line:11 language:Vala diff --git a/Units/parser-vala.r/comments.vala.d/input.vala b/Units/parser-vala.r/comments.vala.d/input.vala new file mode 100644 index 0000000000..ed4cfe902a --- /dev/null +++ b/Units/parser-vala.r/comments.vala.d/input.vala @@ -0,0 +1,11 @@ +void f1 () { + print ("hello"); +} +// void g0 () { print ("hello");} + // void g1 () { print ("hello");} + +void f2 () {print ("hello");} // void g3 () { print ("hello");} +void f3 () {print ("hello");} void g4 () { print ("hello");} +void f4 () {print ("hello"); // void g5 () { print ("hello");} +// void g6 () { print ("hello");} +} void g7 () { print ("hello");} // void g8 () {} ; void f5 () { print ("hello");} # void g9 () {} diff --git a/Units/parser-vala.r/functions.vala.d/args.ctags b/Units/parser-vala.r/functions.vala.d/args.ctags new file mode 100644 index 0000000000..3bba6778c9 --- /dev/null +++ b/Units/parser-vala.r/functions.vala.d/args.ctags @@ -0,0 +1,2 @@ +--sort=no +--fields=+neKl diff --git a/Units/parser-vala.r/functions.vala.d/expected.tags b/Units/parser-vala.r/functions.vala.d/expected.tags new file mode 100644 index 0000000000..62814d8917 --- /dev/null +++ b/Units/parser-vala.r/functions.vala.d/expected.tags @@ -0,0 +1,2 @@ +main input.vala /^void main(string[] args) {$/;" method line:4 language:Vala +sum input.vala /^int sum(int sum1, int sum2) {$/;" method line:8 language:Vala diff --git a/Units/parser-vala.r/functions.vala.d/input.vala b/Units/parser-vala.r/functions.vala.d/input.vala new file mode 100644 index 0000000000..3466ab552a --- /dev/null +++ b/Units/parser-vala.r/functions.vala.d/input.vala @@ -0,0 +1,10 @@ +/* + * vala sum + */ +void main(string[] args) { + print("Sum is: %d\n", sum(1,2)); +} + +int sum(int sum1, int sum2) { + return sum1 + sum2; +} diff --git a/Units/parser-vala.r/namespace.vala.d/expected.tags b/Units/parser-vala.r/namespace.vala.d/expected.tags new file mode 100644 index 0000000000..e1039b1e0c --- /dev/null +++ b/Units/parser-vala.r/namespace.vala.d/expected.tags @@ -0,0 +1,17 @@ +Address input.vala /^ class Address {$/;" c namespace:Data +Contact input.vala /^ class Contact {$/;" c namespace:Data.Private +Data input.vala /^namespace Data {$/;" n +Person input.vala /^class Person {$/;" c +Private input.vala /^ namespace Private {$/;" n namespace:Data +address input.vala /^ public Data.Address address {get; set;}$/;" p class:Person typeref:class:Data.Address +building input.vala /^ public int building;$/;" f class:Data.Address typeref:typename:int +city input.vala /^ public string city;$/;" f class:Data.Address typeref:typename:string +country input.vala /^ public string country;$/;" f class:Data.Address typeref:typename:string +d_street input.vala /^ public string d_street;$/;" f class:Data.Address typeref:typename:string +email input.vala /^ public string email;$/;" f class:Data.Private.Contact typeref:typename:string +floor input.vala /^ public int floor;$/;" f class:Data.Address typeref:typename:int +id input.vala /^ public string id;$/;" f class:Data.Private.Contact typeref:typename:string +main input.vala /^void main(string[] args) {$/;" m +name input.vala /^ public string name {get; set;}$/;" p class:Person typeref:typename:string +phone input.vala /^ public string phone;$/;" f class:Data.Private.Contact typeref:typename:string +street input.vala /^ public string street {$/;" p class:Data.Address typeref:typename:string diff --git a/Units/parser-vala.r/namespace.vala.d/input.vala b/Units/parser-vala.r/namespace.vala.d/input.vala new file mode 100644 index 0000000000..46efe6ffa5 --- /dev/null +++ b/Units/parser-vala.r/namespace.vala.d/input.vala @@ -0,0 +1,55 @@ +using Data; + +void main(string[] args) { + var p = new Person(); + var a = new Address(); + a.street = "Oxford Street"; + p.address = a; + p.name = "John"; + p.age = 21; + print("Hello %s, you're %d years old\nliving in %s\n", p.name, p.age, p.address.street); +} + +namespace Data { + class Address { + public string country; + public string city; + public string d_street; + public int building; + public int floor; + + public string street { + owned get { + return d_street; + } + set { + d_street = value; + } + } + } + + namespace Private { + class Contact { + public string email; + public string phone; + public string id; + } + } +} + +class Person { + public Data.Address address {get; set;} + public string name {get; set;} + private int d_age; + + public int age { + get { return d_age;} + set { + if (value > 0) { + d_age = value; + } else { + d_age = 0; + } + } + } +} diff --git a/Units/parser-vala.r/simple.vala.d/args.ctags b/Units/parser-vala.r/simple.vala.d/args.ctags new file mode 100644 index 0000000000..3bba6778c9 --- /dev/null +++ b/Units/parser-vala.r/simple.vala.d/args.ctags @@ -0,0 +1,2 @@ +--sort=no +--fields=+neKl diff --git a/Units/parser-vala.r/simple.vala.d/expected.tags b/Units/parser-vala.r/simple.vala.d/expected.tags new file mode 100644 index 0000000000..000700e9ac --- /dev/null +++ b/Units/parser-vala.r/simple.vala.d/expected.tags @@ -0,0 +1 @@ +main input.vala /^void main(string[] args) {$/;" method line:4 language:Vala diff --git a/Units/parser-vala.r/simple.vala.d/input.vala b/Units/parser-vala.r/simple.vala.d/input.vala new file mode 100644 index 0000000000..0f4c815972 --- /dev/null +++ b/Units/parser-vala.r/simple.vala.d/input.vala @@ -0,0 +1,6 @@ +/* + * vala HelloWorld + */ +void main(string[] args) { + print("Hello, World\n"); +} diff --git a/main/parsers_p.h b/main/parsers_p.h index 2f2e50bffd..0b91690153 100644 --- a/main/parsers_p.h +++ b/main/parsers_p.h @@ -140,8 +140,8 @@ VeraParser, \ VerilogParser, \ SystemVerilogParser, \ - VhdlParser, \ ValaParser, \ + VhdlParser, \ VimParser, \ WindResParser, \ YaccParser, \ diff --git a/parsers/vala.c b/parsers/vala.c index cbbdc7322d..0b3662056c 100644 --- a/parsers/vala.c +++ b/parsers/vala.c @@ -1,10 +1,11 @@ /* -* Copyright (c) 2019, +* Copyright (c) 2019, Masatake Yamato +* Copyright (c) 2019, Alberto Fanjul * * This source code is released for free distribution under the terms of the * GNU General Public License version 2 or (at your option) any later version. * -* This module contains functions for parsing and scanning Vaka source files. +* This module contains functions for parsing and scanning Vala source files. */ /* @@ -35,33 +36,194 @@ typedef enum { K_UNDEFINED = -1, K_CLASS, + K_STRUCT, + K_INTERFACE, + K_ENUM, + K_ENUMVALUE, + K_ERRORDOMAIN, + K_ERRORCODE, + K_DELEGATE, + K_SIGNAL, K_FIELD, K_METHOD, K_PROP, + K_LOCAL, + K_NAMESPACE, + COUNT_KIND } valaKind; static kindDefinition ValaKinds [] = { - { true, 'c', "class", "classes"}, - { true, 'f', "field", "fields"}, - { true, 'm', "method", "methods"}, - { true, 'p', "property", "properties"}, + { true, 'c', "class", "classes" }, + { true, 's', "struct", "structures" }, + { true, 'i', "interface", "interfaces" }, + { true, 'e', "enum", "enumerations" }, + { true, 'v', "enumvalue", "enumeration Values" }, + { true, 'E', "errordomain", "error domains" }, + { true, 'r', "errorcode", "error codes" }, + { true, 'd', "delegate", "delegates" }, + { true, 'S', "signal", "signals" }, + { true, 'f', "field", "fields" }, + { true, 'm', "method", "methods" }, + { true, 'p', "property", "properties" }, + { false, 'l', "local", "local variables" }, + { true, 'n', "namespace", "namespace" }, }; enum eKeywordId { - KEYWORD_CLASS, - KEYWORD_PUBLIC, KEYWORD_STRING, + KEYWORD_INT, + KEYWORD_DOUBLE, + KEYWORD_FLOAT, + KEYWORD_BOOL, KEYWORD_VOID, + KEYWORD_TYPE, + KEYWORD_ABSTRACT, + KEYWORD_AS, + KEYWORD_ASYNC, + KEYWORD_BASE, + KEYWORD_BREAK, + KEYWORD_CASE, + KEYWORD_CATCH, + KEYWORD_CLASS, + KEYWORD_CONST, + KEYWORD_CONSTRUCT, + KEYWORD_CONTINUE, + KEYWORD_DEFAULT, + KEYWORD_DELEGATE, + KEYWORD_DELETE, + KEYWORD_DO, + KEYWORD_DYNAMIC, + KEYWORD_ELSE, + KEYWORD_ENSURES, + KEYWORD_ENUM, + KEYWORD_ERRORDOMAIN, + KEYWORD_EXTERN, + KEYWORD_FALSE, + KEYWORD_FINALLY, + KEYWORD_FOR, + KEYWORD_FOREACH, + KEYWORD_GET, + KEYWORD_GLOBAL, + KEYWORD_IF, + KEYWORD_IN, + KEYWORD_INLINE, + KEYWORD_INTERFACE, + KEYWORD_INTERNAL, + KEYWORD_IS, + KEYWORD_LOCK, + KEYWORD_NAMESPACE, + KEYWORD_NEW, + KEYWORD_NULL, + KEYWORD_OUT, + KEYWORD_OVERRIDE, + KEYWORD_OWNED, + KEYWORD_PRIVATE, + KEYWORD_PROTECTED, + KEYWORD_PUBLIC, + KEYWORD_REF, + KEYWORD_REQUIRES, + KEYWORD_RETURN, + KEYWORD_SET, + KEYWORD_SIGNAL, + KEYWORD_SIZEOF, + KEYWORD_STATIC, + KEYWORD_STRUCT, + KEYWORD_SWITCH, + KEYWORD_THIS, + KEYWORD_THROW, + KEYWORD_THROWS, + KEYWORD_TRUE, + KEYWORD_TRY, + KEYWORD_TYPEOF, + KEYWORD_UNOWNED, + KEYWORD_USING, + KEYWORD_VALUE, + KEYWORD_VAR, + KEYWORD_VIRTUAL, + KEYWORD_WEAK, + KEYWORD_WHILE, + KEYWORD_YIELD, + }; typedef int keywordId; /* to allow KEYWORD_NONE */ static const keywordTable ValaKeywordTable [] = { - { "class", KEYWORD_CLASS }, - { "public", KEYWORD_PUBLIC }, { "string", KEYWORD_STRING }, + { "int", KEYWORD_INT }, + { "double", KEYWORD_DOUBLE }, + { "float", KEYWORD_FLOAT }, + { "bool", KEYWORD_BOOL }, + { "void", KEYWORD_VOID }, + { "Type", KEYWORD_TYPE }, + { "abstract", KEYWORD_ABSTRACT }, + { "as", KEYWORD_AS }, + { "async", KEYWORD_ASYNC }, + { "base", KEYWORD_BASE }, + { "break", KEYWORD_BREAK }, + { "case", KEYWORD_CASE }, + { "catch", KEYWORD_CATCH }, + { "class", KEYWORD_CLASS }, + { "const", KEYWORD_CONST }, + { "construct", KEYWORD_CONSTRUCT }, + { "continue", KEYWORD_CONTINUE }, + { "default", KEYWORD_DEFAULT }, + { "delegate", KEYWORD_DELEGATE }, + { "delete", KEYWORD_DELETE }, + { "do", KEYWORD_DO }, + { "dynamic", KEYWORD_DYNAMIC }, + { "else", KEYWORD_ELSE }, + { "ensures", KEYWORD_ENSURES }, + { "enum", KEYWORD_ENUM }, + { "errordomain", KEYWORD_ERRORDOMAIN }, + { "extern", KEYWORD_EXTERN }, + { "false", KEYWORD_FALSE }, + { "finally", KEYWORD_FINALLY }, + { "for", KEYWORD_FOR }, + { "foreach", KEYWORD_FOREACH }, + { "get", KEYWORD_GET }, + { "global", KEYWORD_GLOBAL }, + { "if", KEYWORD_IF }, + { "in", KEYWORD_IN }, + { "inline", KEYWORD_INLINE }, + { "interface", KEYWORD_INTERFACE }, + { "internal", KEYWORD_INTERNAL }, + { "is", KEYWORD_IS }, + { "lock", KEYWORD_LOCK }, + { "namespace", KEYWORD_NAMESPACE }, + { "new", KEYWORD_NEW }, + { "null", KEYWORD_NULL }, + { "out", KEYWORD_OUT }, + { "override", KEYWORD_OVERRIDE }, + { "owned", KEYWORD_OWNED }, + { "private", KEYWORD_PRIVATE }, + { "protected", KEYWORD_PROTECTED }, + { "public", KEYWORD_PUBLIC }, + { "ref", KEYWORD_REF }, + { "requires", KEYWORD_REQUIRES }, + { "return", KEYWORD_RETURN }, + { "set", KEYWORD_SET }, + { "signal", KEYWORD_SIGNAL }, + { "sizeof", KEYWORD_SIZEOF }, + { "static", KEYWORD_STATIC }, + { "struct", KEYWORD_STRUCT }, + { "switch", KEYWORD_SWITCH }, + { "this", KEYWORD_THIS }, + { "throw", KEYWORD_THROW }, + { "throws", KEYWORD_THROWS }, + { "true", KEYWORD_TRUE }, + { "try", KEYWORD_TRY }, + { "typeof", KEYWORD_TYPEOF }, + { "unowned", KEYWORD_UNOWNED }, + { "using", KEYWORD_USING }, + { "value", KEYWORD_VALUE }, + { "var", KEYWORD_VAR }, + { "virtual", KEYWORD_VIRTUAL }, + { "weak", KEYWORD_WEAK }, + { "while", KEYWORD_WHILE }, + { "yield", KEYWORD_YIELD }, }; enum ValaTokenType { @@ -80,6 +242,9 @@ enum ValaTokenType { */ static void readToken (tokenInfo *const token, void *data); +static void parseNamespace (tokenInfo *const token, int corkIndex); +static void parseClass (tokenInfo *const token, int corkIndex); +static void parseStatement (tokenInfo *const token, int corkIndex); /* @@ -90,6 +255,7 @@ static struct tokenTypePair typePairs [] = { { '{', '}' }, { '[', ']' }, { '(', ')' }, + { '<', '>' }, }; static struct tokenInfoClass valaTokenInfoClass = { @@ -172,7 +338,7 @@ static void readIdentifier (tokenInfo *token) static void readToken (tokenInfo *const token, void *data) { int c; - bool semi_terminaotr = false; + bool semi_terminator = false; token->type = TOKEN_UNDEFINED; token->keyword = KEYWORD_NONE; @@ -256,8 +422,10 @@ static void readToken (tokenInfo *const token, void *data) case '}': case ']': case ')': + case '<': + case '>': case ';': - semi_terminaotr = true; + semi_terminator = true; case '{': case '[': case '(': @@ -292,7 +460,7 @@ static void readToken (tokenInfo *const token, void *data) vStringCat (collector, token->string); else { - if (!semi_terminaotr + if (!semi_terminator && !strchr ("{[(", vStringLast(collector))) vStringPut(collector, ' '); vStringCat (collector, token->string); @@ -305,7 +473,7 @@ static tokenInfo *newValaToken (void) return newToken (&valaTokenInfoClass); } -static void parseStatement (tokenInfo *const token) +static void parseStatement (tokenInfo *const token, int corkIndex) { tokenInfo *lastToken = newValaToken (); bool foundSignature = false; @@ -316,16 +484,20 @@ static void parseStatement (tokenInfo *const token) tokenRead (token); if (tokenEqType (token, '(')) { - vString *signature = vStringNewInit ("("); - int corkIndex = makeSimpleTag (lastToken->string, K_METHOD); - foundSignature = tokenSkipOverPairFull (token, signature); - if (foundSignature) - { - tagEntryInfo *e = getEntryInCorkQueue (corkIndex); - e->extensionFields.signature = vStringDeleteUnwrap (signature); - } - else - vStringDelete (signature); + if (tokenIsType (lastToken, KEYWORD)) { + tokenSkipOverPair (token); + } else { + vString *signature = vStringNewInit ("("); + int corkIndex = makeSimpleTag (lastToken->string, K_METHOD); + foundSignature = tokenSkipOverPairFull (token, signature); + if (foundSignature) + { + tagEntryInfo *e = getEntryInCorkQueue (corkIndex); + e->extensionFields.signature = vStringDeleteUnwrap (signature); + } + else + vStringDelete (signature); + } break; } } @@ -340,6 +512,35 @@ static void parseStatement (tokenInfo *const token) tokenDestroy (lastToken); } +static void recurseValaTags (tokenInfo *token, int corkIndex) +{ + if (tokenIsKeyword(token, NAMESPACE)) + parseNamespace (token, corkIndex); + if (tokenIsKeyword(token, CLASS)) + parseClass (token, corkIndex); + else if (tokenIsType (token, IDENTIFIER)) + parseStatement (token, corkIndex); +} + +static void parseNamespaceBody (tokenInfo *const token, int corkIndex) +{ + tokenInfo *typerefToken = newValaToken (); + tokenInfo *nameToken = newValaToken (); + + do + { + tokenRead (token); + if (tokenEqType (token, '}')) + break; + + recurseValaTags (token, corkIndex); + + if (tokenEqType (token, '{')) + tokenSkipOverPair (token); + + } while (!tokenIsEOF (token)); +} + static bool readIdentifierExtended (tokenInfo *const resultToken, bool *extended) { bool nextTokeIsIdentifier = false; @@ -454,13 +655,33 @@ static void parseClassBody (tokenInfo *const token, int classCorkIndex) tokenDestroy (nameToken); } -static void parseClass (tokenInfo *const token) +static void parseNamespace (tokenInfo *const token, int corkIndex) +{ + + tokenRead (token); + if (!tokenIsType (token, IDENTIFIER)) + return; /* Unexpected sequence of token */ + + int namespaceCorkIndex = makeSimpleTag (token->string, K_NAMESPACE); + tagEntryInfo *entry = getEntryInCorkQueue (namespaceCorkIndex); + entry->extensionFields.scopeIndex = corkIndex; + + tokenRead (token); + if (!tokenSkipToType (token, '{')) + return; /* Unexpected sequence of token */ + + parseNamespaceBody (token, namespaceCorkIndex); +} + +static void parseClass (tokenInfo *const token, int corkIndex) { tokenRead (token); if (!tokenIsType (token, IDENTIFIER)) return; /* Unexpected sequence of token */ int classCorkIndex = makeSimpleTag (token->string, K_CLASS); + tagEntryInfo *entry = getEntryInCorkQueue (classCorkIndex); + entry->extensionFields.scopeIndex = corkIndex; /* Skip the class definition. */ tokenRead (token); @@ -476,11 +697,7 @@ static void findValaTags (void) do { tokenRead (token); - if (tokenIsKeyword(token, CLASS)) - parseClass (token); - else if (tokenIsType (token, IDENTIFIER) - || tokenIsType (token, KEYWORD)) - parseStatement (token); + recurseValaTags (token, CORK_NIL); } while (!tokenIsEOF (token)); diff --git a/win32/ctags_vs2013.vcxproj b/win32/ctags_vs2013.vcxproj index 0842c94191..1d8e64fc7b 100644 --- a/win32/ctags_vs2013.vcxproj +++ b/win32/ctags_vs2013.vcxproj @@ -248,6 +248,7 @@ +