diff --git a/Tmain/list-fields-with-prefix.d/stdout-expected.txt b/Tmain/list-fields-with-prefix.d/stdout-expected.txt index 898a490932..8fd19ed4db 100644 --- a/Tmain/list-fields-with-prefix.d/stdout-expected.txt +++ b/Tmain/list-fields-with-prefix.d/stdout-expected.txt @@ -44,4 +44,5 @@ x UCTAGSxpath no NONE s-- no -- xpath for - UCTAGStarget yes Thrift s-- no -- the target language specified at "namespace" - UCTAGSthrows yes Thrift s-- no -- throws list of function - UCTAGSarchitecture yes VHDL s-- no -- architecture designing the entity +- UCTAGSproperties yes Vala s-- no -- properties (static) - UCTAGSparameter no Verilog --b no -- parameter whose value can be overridden. diff --git a/Tmain/list-fields.d/stdout-expected.txt b/Tmain/list-fields.d/stdout-expected.txt index d05ad961de..5da66406d4 100644 --- a/Tmain/list-fields.d/stdout-expected.txt +++ b/Tmain/list-fields.d/stdout-expected.txt @@ -62,6 +62,7 @@ z kind no NONE s-- no r- [tags output] prepend "kind:" to k/ (or K/) field outpu - target yes Thrift s-- no -- the target language specified at "namespace" - throws yes Thrift s-- no -- throws list of function - architecture yes VHDL s-- no -- architecture designing the entity +- properties yes Vala s-- no -- properties (static) - parameter no Verilog --b no -- parameter whose value can be overridden. # Foo input.java /^abstract public class Foo extends Bar$/ 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/attributes.vala.d/args.ctags b/Units/parser-vala.r/attributes.vala.d/args.ctags new file mode 100644 index 0000000000..3bba6778c9 --- /dev/null +++ b/Units/parser-vala.r/attributes.vala.d/args.ctags @@ -0,0 +1,2 @@ +--sort=no +--fields=+neKl diff --git a/Units/parser-vala.r/attributes.vala.d/expected.tags b/Units/parser-vala.r/attributes.vala.d/expected.tags new file mode 100644 index 0000000000..e266837743 --- /dev/null +++ b/Units/parser-vala.r/attributes.vala.d/expected.tags @@ -0,0 +1 @@ +Delegate input.vala /^public delegate bool Delegate ();$/;" method line:2 language:Vala end:2 diff --git a/Units/parser-vala.r/attributes.vala.d/input.vala b/Units/parser-vala.r/attributes.vala.d/input.vala new file mode 100644 index 0000000000..6d7033e53c --- /dev/null +++ b/Units/parser-vala.r/attributes.vala.d/input.vala @@ -0,0 +1,2 @@ +[CCode (has_target="false")] +public delegate bool Delegate (); 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..2c02d04a86 --- /dev/null +++ b/Units/parser-vala.r/class.vala.d/args.ctags @@ -0,0 +1,2 @@ +--sort=no +--fields=+neKl{signature}{access} 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..edfe138fcf --- /dev/null +++ b/Units/parser-vala.r/class.vala.d/expected.tags @@ -0,0 +1,26 @@ +main input.vala /^void main(string[] args) {$/;" method line:8 language:Vala signature:(string [] args) end:13 +Address input.vala /^public class Address {$/;" class line:15 language:Vala end:21 +country input.vala /^ string country;$/;" field line:16 language:Vala class:Address typeref:typename:string end:16 +city input.vala /^ public string city;$/;" field line:17 language:Vala class:Address typeref:typename:string access:public end:17 +street input.vala /^ protected string street;$/;" field line:18 language:Vala class:Address typeref:typename:string access:protected end:18 +building input.vala /^ internal int building;$/;" field line:19 language:Vala class:Address typeref:typename:int access:internal end:19 +floor input.vala /^ private int floor;$/;" field line:20 language:Vala class:Address typeref:typename:int access:private end:20 +Person input.vala /^class Person {$/;" class line:23 language:Vala end:45 +address input.vala /^ public Address address {get; set;}$/;" property line:24 language:Vala class:Person typeref:unknown:Address access:public end:24 +name input.vala /^ public string name {get; set;}$/;" property line:25 language:Vala class:Person typeref:typename:string access:public end:25 +d_age input.vala /^ private int d_age;$/;" field line:26 language:Vala class:Person typeref:typename:int access:private end:26 +population input.vala /^ static int population;$/;" field line:28 language:Vala class:Person typeref:typename:int end:28 properties:static +age input.vala /^ public int age {$/;" property line:30 language:Vala class:Person typeref:typename:int access:public end:39 +getLastAge input.vala /^ int getLastAge (int n) throws GLib.Error { return d_age - n; }$/;" method line:41 language:Vala class:Person typeref:typename:int signature:(int n) end:41 +table input.vala /^ string [] table = {"a", "b"};$/;" field line:43 language:Vala class:Person typeref:typename:string end:43 +ctable input.vala /^ const string [] ctable = {"a", "b"};$/;" field line:44 language:Vala class:Person typeref:typename:string end:44 +Car input.vala /^public class Car {$/;" class line:47 language:Vala end:66 +n_seat input.vala /^ public int n_seat;$/;" field line:48 language:Vala class:Car typeref:typename:int access:public end:48 +Car input.vala /^ public Car () {$/;" method line:49 language:Vala class:Car access:public signature:() end:51 +sctable input.vala /^ static const string [] sctable = {"a", "b"};$/;" field line:52 language:Vala class:Car typeref:typename:string end:52 properties:static +@get input.vala /^ public new string? @get (string key) {$/;" method line:54 language:Vala class:Car typeref:typename:string access:public signature:(string key) end:56 +value_changed input.vala /^ public signal void value_changed (string name, Variant value);$/;" signal line:58 language:Vala class:Car typeref:typename:void access:public signature:(string name, Variant value) end:58 +addSeat input.vala /^ int addSeat (int n) { return n_seat + n; }$/;" method line:59 language:Vala class:Car typeref:typename:int signature:(int n) end:59 +Seat input.vala /^ public class Seat {$/;" class line:61 language:Vala class:Car end:63 +x input.vala /^ int x;$/;" field line:62 language:Vala class:Car.Seat typeref:typename:int end:62 +more input.vala /^ public int more;$/;" field line:65 language:Vala class:Car typeref:typename:int access:public end:65 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..20cec09893 --- /dev/null +++ b/Units/parser-vala.r/class.vala.d/input.vala @@ -0,0 +1,66 @@ +/* + * 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); +} + +public class Address { + string country; + public string city; + protected string street; + internal int building; + private int floor; +} + +class Person { + public Address address {get; set;} + public string name {get; set;} + private int d_age; + + static int population; + + public int age { + get { return d_age;} + set { + if (value > 0) { + d_age = value; + } else { + d_age = 0; + } + } + } + + int getLastAge (int n) throws GLib.Error { return d_age - n; } + + string [] table = {"a", "b"}; + const string [] ctable = {"a", "b"}; +} + +public class Car { + public int n_seat; + public Car () { + n_seat = 0; + } + static const string [] sctable = {"a", "b"}; + + public new string? @get (string key) { + return null; + } + + public signal void value_changed (string name, Variant value); + int addSeat (int n) { return n_seat + n; } + + public class Seat { + int x; + } + + public int more; +} 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..3eafc8aa3b --- /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 end:3 +f2 input.vala /^void f2 () {print ("hello");} \/\/ void g3 () { print ("hello");}$/;" method line:7 language:Vala end:7 +f3 input.vala /^void f3 () {print ("hello");} void g4 () { print ("hello");}$/;" method line:8 language:Vala end:8 +g4 input.vala /^void f3 () {print ("hello");} void g4 () { print ("hello");}$/;" method line:8 language:Vala end:8 +f4 input.vala /^void f4 () {print ("hello"); \/\/ void g5 () { print ("hello");}$/;" method line:9 language:Vala end:11 +g7 input.vala /^} void g7 () { print ("hello");} \/\/ void g8 () {} ; void f5 () { print ("hello");} # void g/;" method line:11 language:Vala end:11 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/construct.d/args.ctags b/Units/parser-vala.r/construct.d/args.ctags new file mode 100644 index 0000000000..5ee5f79f70 --- /dev/null +++ b/Units/parser-vala.r/construct.d/args.ctags @@ -0,0 +1 @@ +--sort=no diff --git a/Units/parser-vala.r/construct.d/expected.tags b/Units/parser-vala.r/construct.d/expected.tags new file mode 100644 index 0000000000..8cf463b109 --- /dev/null +++ b/Units/parser-vala.r/construct.d/expected.tags @@ -0,0 +1,2 @@ +Abc input.vala /^class Abc : Object {$/;" c +main input.vala /^void main(string[] args) {}$/;" m diff --git a/Units/parser-vala.r/construct.d/input.vala b/Units/parser-vala.r/construct.d/input.vala new file mode 100644 index 0000000000..16b2c60637 --- /dev/null +++ b/Units/parser-vala.r/construct.d/input.vala @@ -0,0 +1,7 @@ +using GLib; + +class Abc : Object { + construct {} +} + +void main(string[] args) {} diff --git a/Units/parser-vala.r/enum.vala.d/args.ctags b/Units/parser-vala.r/enum.vala.d/args.ctags new file mode 100644 index 0000000000..5ee5f79f70 --- /dev/null +++ b/Units/parser-vala.r/enum.vala.d/args.ctags @@ -0,0 +1 @@ +--sort=no diff --git a/Units/parser-vala.r/enum.vala.d/expected.tags b/Units/parser-vala.r/enum.vala.d/expected.tags new file mode 100644 index 0000000000..213e9a006c --- /dev/null +++ b/Units/parser-vala.r/enum.vala.d/expected.tags @@ -0,0 +1,30 @@ +Skk input.vala /^namespace Skk {$/;" n +KeyEventFormatError input.vala /^ public errordomain KeyEventFormatError {$/;" E namespace:Skk +PARSE_FAILED input.vala /^ PARSE_FAILED,$/;" r errordomain:Skk.KeyEventFormatError +KEYSYM_NOT_FOUND input.vala /^ KEYSYM_NOT_FOUND$/;" r errordomain:Skk.KeyEventFormatError +ModifierType input.vala /^ public enum ModifierType {$/;" e namespace:Skk +NONE input.vala /^ NONE = 0,$/;" v enum:Skk.ModifierType +SHIFT_MASK input.vala /^ SHIFT_MASK = 1 << 0,$/;" v enum:Skk.ModifierType +LOCK_MASK input.vala /^ LOCK_MASK = 1 << 1,$/;" v enum:Skk.ModifierType +CONTROL_MASK input.vala /^ CONTROL_MASK = 1 << 2,$/;" v enum:Skk.ModifierType +MOD1_MASK input.vala /^ MOD1_MASK = 1 << 3,$/;" v enum:Skk.ModifierType +MOD2_MASK input.vala /^ MOD2_MASK = 1 << 4,$/;" v enum:Skk.ModifierType +MOD3_MASK input.vala /^ MOD3_MASK = 1 << 5,$/;" v enum:Skk.ModifierType +MOD4_MASK input.vala /^ MOD4_MASK = 1 << 6,$/;" v enum:Skk.ModifierType +MOD5_MASK input.vala /^ MOD5_MASK = 1 << 7,$/;" v enum:Skk.ModifierType +LSHIFT_MASK input.vala /^ LSHIFT_MASK = 1 << 22,$/;" v enum:Skk.ModifierType +RSHIFT_MASK input.vala /^ RSHIFT_MASK = 1 << 23,$/;" v enum:Skk.ModifierType +USLEEP_MASK input.vala /^ USLEEP_MASK = 1 << 24,$/;" v enum:Skk.ModifierType +SUPER_MASK input.vala /^ SUPER_MASK = 1 << 26,$/;" v enum:Skk.ModifierType +HYPER_MASK input.vala /^ HYPER_MASK = 1 << 27,$/;" v enum:Skk.ModifierType +META_MASK input.vala /^ META_MASK = 1 << 28,$/;" v enum:Skk.ModifierType +RELEASE_MASK input.vala /^ RELEASE_MASK = 1 << 30$/;" v enum:Skk.ModifierType +ModifierType2 input.vala /^ public enum ModifierType2 {$/;" e namespace:Skk +ULTRA_MASK input.vala /^ ULTRA_MASK = 1 << 20,$/;" v enum:Skk.ModifierType2 +MIRACLE_MASK input.vala /^ MIRACLE_MASK = 1 << 21, \/\/ valac accept this.$/;" v enum:Skk.ModifierType2 +ModifierType3 input.vala /^ public enum ModifierType3 {$/;" e namespace:Skk +A_MASK input.vala /^ A_MASK = 1 << 29,$/;" v enum:Skk.ModifierType3 +B_MASK input.vala /^ B_MASK = 1 << 31;$/;" v enum:Skk.ModifierType3 +to_string0 input.vala /^ string to_string0() {$/;" m enum:Skk.ModifierType3 +to_string1 input.vala /^ string to_string1() {$/;" m enum:Skk.ModifierType3 +KeyEvent input.vala /^ public class KeyEvent : Object {$/;" c namespace:Skk diff --git a/Units/parser-vala.r/enum.vala.d/input.vala b/Units/parser-vala.r/enum.vala.d/input.vala new file mode 100644 index 0000000000..4d99cdd185 --- /dev/null +++ b/Units/parser-vala.r/enum.vala.d/input.vala @@ -0,0 +1,78 @@ +/* Taken from https://github.com/ueno/libskk + * (libskk/libskk/key-event.vala) + */ + +/* + * Copyright (C) 2011-2018 Daiki Ueno + * Copyright (C) 2011-2018 Red Hat, Inc. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +using Gee; + +namespace Skk { + public errordomain KeyEventFormatError { + PARSE_FAILED, + KEYSYM_NOT_FOUND + } + + /** + * A set of bit-flags to indicate the state of modifier keys. + */ + [Flags] + public enum ModifierType { + NONE = 0, + SHIFT_MASK = 1 << 0, + LOCK_MASK = 1 << 1, + CONTROL_MASK = 1 << 2, + MOD1_MASK = 1 << 3, + MOD2_MASK = 1 << 4, + MOD3_MASK = 1 << 5, + MOD4_MASK = 1 << 6, + MOD5_MASK = 1 << 7, + + // dummy modifiers for NICOLA + LSHIFT_MASK = 1 << 22, + RSHIFT_MASK = 1 << 23, + USLEEP_MASK = 1 << 24, + + SUPER_MASK = 1 << 26, + HYPER_MASK = 1 << 27, + META_MASK = 1 << 28, + RELEASE_MASK = 1 << 30 + } + + public enum ModifierType2 { + ULTRA_MASK = 1 << 20, + MIRACLE_MASK = 1 << 21, // valac accept this. + } + + public enum ModifierType3 { + A_MASK = 1 << 29, + B_MASK = 1 << 31; + string to_string0() { + return ""; + } + string to_string1() { + return ""; + } + } + + /** + * Object representing a key event. + */ + public class KeyEvent : Object { + /* ... */ + } +} 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..0e201d551b --- /dev/null +++ b/Units/parser-vala.r/functions.vala.d/args.ctags @@ -0,0 +1,2 @@ +--sort=no +--fields=+neKl{signature} 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..439cd9aa3b --- /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 signature:(string [] args) end:6 +sum input.vala /^int sum(int sum1, int sum2) {$/;" method line:8 language:Vala signature:(int sum1, int sum2) end:10 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/inheritance-list.d/args.ctags b/Units/parser-vala.r/inheritance-list.d/args.ctags new file mode 100644 index 0000000000..cace191508 --- /dev/null +++ b/Units/parser-vala.r/inheritance-list.d/args.ctags @@ -0,0 +1,2 @@ +--sort=no +--fields=+i diff --git a/Units/parser-vala.r/inheritance-list.d/expected.tags b/Units/parser-vala.r/inheritance-list.d/expected.tags new file mode 100644 index 0000000000..c8441163ad --- /dev/null +++ b/Units/parser-vala.r/inheritance-list.d/expected.tags @@ -0,0 +1,5 @@ +AXc input.vala /^public class AXc {$/;" c +a input.vala /^ int a;$/;" f class:AXc typeref:typename:int +BXi input.vala /^public interface BXi {$/;" i +MyObject input.vala /^public class MyObject: AXc, BXi {$/;" c inherits:AXc,BXi +c input.vala /^ int c;$/;" f class:MyObject typeref:typename:int diff --git a/Units/parser-vala.r/inheritance-list.d/input.vala b/Units/parser-vala.r/inheritance-list.d/input.vala new file mode 100644 index 0000000000..82d68b211a --- /dev/null +++ b/Units/parser-vala.r/inheritance-list.d/input.vala @@ -0,0 +1,10 @@ +public class AXc { + int a; +} + +public interface BXi { +} + +public class MyObject: AXc, BXi { + int c; +} diff --git a/Units/parser-vala.r/namespace.vala.d/args.ctags b/Units/parser-vala.r/namespace.vala.d/args.ctags new file mode 100644 index 0000000000..3a2f45774d --- /dev/null +++ b/Units/parser-vala.r/namespace.vala.d/args.ctags @@ -0,0 +1,2 @@ +--sort=no +--fields=+ea 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..68a7d290e0 --- /dev/null +++ b/Units/parser-vala.r/namespace.vala.d/expected.tags @@ -0,0 +1,19 @@ +main input.vala /^void main(string[] args) {$/;" m end:11 +Data input.vala /^namespace Data {$/;" n end:38 +Address input.vala /^ class Address {$/;" c namespace:Data end:29 +country input.vala /^ public string country;$/;" f class:Data.Address typeref:typename:string access:public end:15 +city input.vala /^ public string city;$/;" f class:Data.Address typeref:typename:string access:public end:16 +d_street input.vala /^ public string d_street;$/;" f class:Data.Address typeref:typename:string access:public end:17 +building input.vala /^ public int building;$/;" f class:Data.Address typeref:typename:int access:public end:18 +floor input.vala /^ public int floor;$/;" f class:Data.Address typeref:typename:int access:public end:19 +street input.vala /^ public string street {$/;" p class:Data.Address typeref:typename:string access:public end:28 +Private input.vala /^ namespace Private {$/;" n namespace:Data end:37 +Contact input.vala /^ class Contact {$/;" c namespace:Data.Private end:36 +email input.vala /^ public string email;$/;" f class:Data.Private.Contact typeref:typename:string access:public end:33 +phone input.vala /^ public string phone;$/;" f class:Data.Private.Contact typeref:typename:string access:public end:34 +id input.vala /^ public string id;$/;" f class:Data.Private.Contact typeref:typename:string access:public end:35 +Person input.vala /^class Person {$/;" c end:55 +address input.vala /^ public Data.Address address {get; set;}$/;" p class:Person typeref:class:Data.Address access:public end:41 +name input.vala /^ public string name {get; set;}$/;" p class:Person typeref:typename:string access:public end:42 +d_age input.vala /^ private int d_age;$/;" f class:Person typeref:typename:int access:private end:43 +age input.vala /^ public int age {$/;" p class:Person typeref:typename:int access:public end:54 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/qnamed-class.d/args.ctags b/Units/parser-vala.r/qnamed-class.d/args.ctags new file mode 100644 index 0000000000..5ee5f79f70 --- /dev/null +++ b/Units/parser-vala.r/qnamed-class.d/args.ctags @@ -0,0 +1 @@ +--sort=no diff --git a/Units/parser-vala.r/qnamed-class.d/expected.tags b/Units/parser-vala.r/qnamed-class.d/expected.tags new file mode 100644 index 0000000000..2f4d3b28c3 --- /dev/null +++ b/Units/parser-vala.r/qnamed-class.d/expected.tags @@ -0,0 +1,6 @@ +X input.vala /^namespace X {$/;" n +X.MyObject input.vala /^public class X.MyObject {$/;" c +a input.vala /^ int a;$/;" f class:X.MyObject typeref:typename:int +b input.vala /^ int b = 1;$/;" f class:X.MyObject typeref:typename:int +c input.vala /^ int c = 2;$/;" f class:X.MyObject typeref:typename:int +d input.vala /^ int d;$/;" f class:X.MyObject typeref:typename:int diff --git a/Units/parser-vala.r/qnamed-class.d/input.vala b/Units/parser-vala.r/qnamed-class.d/input.vala new file mode 100644 index 0000000000..95db054dfe --- /dev/null +++ b/Units/parser-vala.r/qnamed-class.d/input.vala @@ -0,0 +1,9 @@ +namespace X { +} + +public class X.MyObject { + int a; + int b = 1; + int c = 2; + int d; +} 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..bc5e950745 --- /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 end:6 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/Units/parser-vala.r/value-types.d/args.ctags b/Units/parser-vala.r/value-types.d/args.ctags new file mode 100644 index 0000000000..5ee5f79f70 --- /dev/null +++ b/Units/parser-vala.r/value-types.d/args.ctags @@ -0,0 +1 @@ +--sort=no diff --git a/Units/parser-vala.r/value-types.d/expected.tags b/Units/parser-vala.r/value-types.d/expected.tags new file mode 100644 index 0000000000..8a4c402219 --- /dev/null +++ b/Units/parser-vala.r/value-types.d/expected.tags @@ -0,0 +1,4 @@ +Vector input.vala /^struct Vector {$/;" s +x input.vala /^ public double x;$/;" f struct:Vector typeref:typename:double +y input.vala /^ public double y;$/;" f struct:Vector typeref:typename:double +z input.vala /^ public double z;$/;" f struct:Vector typeref:typename:double diff --git a/Units/parser-vala.r/value-types.d/input.vala b/Units/parser-vala.r/value-types.d/input.vala new file mode 100644 index 0000000000..9bd9688262 --- /dev/null +++ b/Units/parser-vala.r/value-types.d/input.vala @@ -0,0 +1,8 @@ +// Taken from https://naaando.gitbooks.io/the-vala-tutorial/content/en/3-basics/3.1-data-types/value-types.html + +/* defining a struct */ +struct Vector { + public double x; + public double y; + public double z; +} diff --git a/main/parsers_p.h b/main/parsers_p.h index 8036a2f9af..b7edba6319 100644 --- a/main/parsers_p.h +++ b/main/parsers_p.h @@ -183,6 +183,7 @@ VeraParser, \ VerilogParser, \ SystemVerilogParser, \ + ValaParser, \ VhdlParser, \ VimParser, \ WindResParser, \ diff --git a/main/tokeninfo.c b/main/tokeninfo.c index 0a0e01d5de..b516ce23b9 100644 --- a/main/tokeninfo.c +++ b/main/tokeninfo.c @@ -5,13 +5,12 @@ * 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 generating tags for Python language -* files. */ #include "general.h" #include "tokeninfo.h" +#include "debug.h" #include "entry.h" #include "read.h" #include "routines.h" @@ -185,15 +184,31 @@ bool tokenSkipOverPair (tokenInfo *token) return tokenSkipOverPairFull(token, NULL); } +static bool isTokenTypePairActive (struct tokenTypePair *pair) +{ + return ((pair->active == NULL) || (*pair->active))? true: false; +} + +static struct tokenTypePair *tokenTypeIsStarterOfPairs (tokenType t, + struct tokenTypePair pairs [], + size_t count) +{ + for (size_t i = 0; i < count; i++) + if (isTokenTypePairActive (pairs +i) && (t == pairs[i].start)) + return pairs + i; + return NULL; +} + bool tokenSkipOverPairFull (tokenInfo *token, void *data) { int start = token->type; int end = token->klass->typeForUndefined; - unsigned int i; - for (i = 0; i < token->klass->pairCount; i++) - if (start == token->klass->pairs[i].start) - end = token->klass->pairs[i].end; + struct tokenTypePair *endp = tokenTypeIsStarterOfPairs (start, + token->klass->pairs, + token->klass->pairCount); + if (endp) + end = endp->end; if (end == token->klass->typeForUndefined) return false; @@ -209,3 +224,71 @@ bool tokenSkipOverPairFull (tokenInfo *token, void *data) return (depth == 0)? true: false; } + +bool tokenSkipToTypes (tokenInfo *token, const tokenType ts[], size_t count) +{ + return tokenSkipToTypesFull (token, ts, count, NULL); +} + +static bool tokenTypeIsMember (tokenType t, const tokenType ts[], size_t count) +{ + for (size_t i = 0; i < count; i++) + if (ts [i] == t) + return true; + return false; +} + +bool tokenSkipToTypesFull (tokenInfo *token, const tokenType ts[], size_t count, void *data) +{ + while (! (tokenIsEOF (token) + || tokenTypeIsMember (token->type, ts, count))) + tokenReadFull (token, data); + + return tokenIsEOF (token)? false: true; +} + +bool tokenSkipToTypeOverPairs (tokenInfo *token, tokenType t) +{ + return tokenSkipToTypeOverPairsFull (token, t, NULL); +} + +bool tokenSkipToTypeOverPairsFull (tokenInfo *token, tokenType t, void *data) +{ + + return tokenSkipToTypesOverPairsFull (token, &t, 1, data); +} + +bool tokenSkipToTypesOverPairs (tokenInfo *token, const tokenType ts[], size_t count) +{ + return tokenSkipToTypesOverPairsFull (token, ts, count, NULL); +} + +bool tokenSkipToTypesOverPairsFull (tokenInfo *token, const tokenType ts[], size_t count, void *data) +{ + while (! (tokenIsEOF (token))) + { + if (tokenTypeIsMember (token->type, ts, count)) + return true; + tokenSkipOverPairFull (token, data); + if (tokenIsEOF (token)) + return false; + tokenReadFull (token, data); + } + return false; +} + +void initTagEntryFromToken (tagEntryInfo *e, tokenInfo *const token, int kindIndex, + int scopeIndex) +{ + initTagEntry (e, tokenString (token), kindIndex); + e->lineNumber = token->lineNumber; + e->filePosition = token->filePosition; + e->extensionFields.scopeIndex = scopeIndex; +} + +int makeSimpleTagFromToken (tokenInfo *const token, int kindIndex, int scopeIndex) +{ + tagEntryInfo e; + initTagEntryFromToken (&e, token, kindIndex, scopeIndex); + return makeTagEntry (&e); +} diff --git a/main/tokeninfo.h b/main/tokeninfo.h index 51360106b7..e31536c304 100644 --- a/main/tokeninfo.h +++ b/main/tokeninfo.h @@ -33,6 +33,15 @@ typedef struct sTokenInfo { struct tokenTypePair { tokenType start; tokenType end; + + /* If the field is NULL or the value pointed by the field is true, + * tokenSkipOverPair and its variants regard the pair as an active + * pair; they will skip over the pair. + * + * The value pointed by the field is false, they regard the pair + * as an inactive pair; they will not skip over the pair. + */ + bool *active; }; #define TOKEN(X) ((tokenInfo *)X) @@ -102,4 +111,14 @@ bool tokenSkipToTypeFull (tokenInfo *token, tokenType t, void *data); bool tokenSkipOverPair (tokenInfo *token); bool tokenSkipOverPairFull (tokenInfo *token, void *data); +bool tokenSkipToTypes (tokenInfo *token, const tokenType ts[], size_t count); +bool tokenSkipToTypesFull (tokenInfo *token, const tokenType ts[], size_t count, void *data); +bool tokenSkipToTypeOverPairs (tokenInfo *token, tokenType t); +bool tokenSkipToTypeOverPairsFull (tokenInfo *token, tokenType t, void *data); +bool tokenSkipToTypesOverPairs (tokenInfo *token, const tokenType ts[], size_t count); +bool tokenSkipToTypesOverPairsFull (tokenInfo *token, const tokenType ts[], size_t count, void *data); + +/* Making a tag from a token */ +void initTagEntryFromToken (tagEntryInfo *e, tokenInfo *const token, int kindIndex, int scopeIndex); +int makeSimpleTagFromToken (tokenInfo *const token, int kindIndex, int scopeIndex); #endif diff --git a/parsers/ldscript.c b/parsers/ldscript.c index c7da533feb..2475e70f42 100644 --- a/parsers/ldscript.c +++ b/parsers/ldscript.c @@ -131,7 +131,7 @@ typedef struct sLdScriptToken { #define LDSCRIPT(TOKEN) ((ldScriptToken *)TOKEN) static struct tokenTypePair ldScriptTypePairs [] = { - { '{', '}' }, + { '{', '}', NULL }, }; static struct tokenInfoClass ldScriptTokenInfoClass = { diff --git a/parsers/r.c b/parsers/r.c index eb9c25848b..cfb7a8242b 100644 --- a/parsers/r.c +++ b/parsers/r.c @@ -194,9 +194,9 @@ static const char *tokenTypeStr(enum RTokenType e); #endif static struct tokenTypePair typePairs [] = { - { '{', '}' }, - { '[', ']' }, - { '(', ')' }, + { '{', '}', NULL }, + { '[', ']', NULL }, + { '(', ')', NULL }, }; typedef struct sRToken { diff --git a/parsers/tcl.c b/parsers/tcl.c index 249486806d..2cf6c220e6 100644 --- a/parsers/tcl.c +++ b/parsers/tcl.c @@ -97,8 +97,8 @@ typedef struct sTclToken { #define TCL_PSTATE(TOKEN) (TCL(TOKEN)->pstate) static struct tokenTypePair typePairs [] = { - { '{', '}' }, - { '[', ']' }, + { '{', '}', NULL }, + { '[', ']', NULL }, }; diff --git a/parsers/vala.c b/parsers/vala.c new file mode 100644 index 0000000000..1bc4ae5981 --- /dev/null +++ b/parsers/vala.c @@ -0,0 +1,1062 @@ +/* +* Copyright (c) 2019, Alberto Fanjul +* Copyright (c) 2020, Masatake Yamato +* Copyright (c) 2020, Red Hat, Inc. +* +* 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 Vala source files. +* https://www.vala-project.org/doc/vala/ +*/ + +/* +* INCLUDE FILES +*/ +#include "general.h" /* must always come first */ + +#include "tokeninfo.h" +#include "parse.h" +#include "read.h" +#include "vstring.h" +#include "keyword.h" +#include "entry.h" + +#include + +/* +* MACROS +*/ + + + +/* +* DATA DEFINITIONS +*/ + +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, '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_BUILTIN_TYPE, + 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 struct keywordGroup valaBuiltInKeywordGroup = { + .value = KEYWORD_BUILTIN_TYPE, + .addingUnlessExisting = false, + .keywords = { + /* type: + * value-type: + * fundamental-struct-type: + * integral-type: */ + "char", + "uchar", + "short", + "ushort", + "int", + "uint", + "long", + "ulong", + "size_t", + "ssize_t", + "int8", + "uint8", + "int16", + "uint16", + "int32", + "uint32", + "int64", + "uint64", + "unichar", + /* type: + * value-type: + * fundamental-struct-type: + * floating-point-type: */ + "float", + "double", + /* type: + * value-type: + * fundamental-struct-type: */ + "bool", + /* type: + * reference-type: */ + "string", + NULL + }, +}; + +static const keywordTable ValaKeywordTable [] = { + { "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 { + /* 0..255 are the byte's value */ + TOKEN_EOF = 256, + TOKEN_UNDEFINED, + TOKEN_KEYWORD, + TOKEN_IDENTIFIER, + TOKEN_EOL, + TOKEN_STRING, +}; + +typedef enum { + F_PROPERTIES, +} valaField; + +static fieldDefinition ValaFields[] = { + { .name = "properties", + .description = "properties (static)", + .enabled = true }, +}; + +/* +* FUNCTION PROTOTYPES +*/ + +static void readToken (tokenInfo *const token, void *data); +static void parseNamespace (tokenInfo *const token, int corkIndex); +static void parseInterface (tokenInfo *const token, int corkIndex); +static void parseClass (tokenInfo *const token, int kindIndex, int corkIndex); +static int parseStatement (tokenInfo *const token, int corkIndex); +static void parseEnum (tokenInfo *const token, int kindIndex, int elementKindIndex, int corkIndex); +static bool recurseValaTags (tokenInfo *token, int parentIndex); + + +/* +* DATA DEFINITIONS +*/ + +static bool trianglePairState = true; +static struct tokenTypePair typePairs [] = { + { '{', '}', NULL }, + { '[', ']', NULL }, + { '(', ')', NULL }, + { '<', '>', &trianglePairState }, +}; + +static struct tokenInfoClass valaTokenInfoClass = { + .nPreAlloc = 4, + .typeForUndefined = TOKEN_UNDEFINED, + .keywordNone = KEYWORD_NONE, + .typeForKeyword = TOKEN_KEYWORD, + .typeForEOF = TOKEN_EOF, + .extraSpace = 0, + .pairs = typePairs, + .pairCount = ARRAY_SIZE (typePairs), + .init = NULL, + .read = readToken, + .clear = NULL, + .copy = NULL, +}; + + +/* +* FUNCTION DEFINITIONS +*/ + +static bool tokenIsEmpty (tokenInfo *token) +{ + return vStringIsEmpty (token->string); +} + +static keywordId resolveKeyword (vString *string) +{ + char *s = vStringValue (string); + static langType lang = LANG_AUTO; + + if (lang == LANG_AUTO) + lang = getInputLanguage (); + + return lookupKeyword (s, lang); +} + +static void readString (tokenInfo *token) +{ + int c; + while (1) + { + c = getcFromInputFile (); + switch (c) + { + case EOF: + return; + case '"': + tokenPutc (token, c); + return; + default: + tokenPutc (token, c); + break; + } + } +} + +static void readIdentifier (tokenInfo *token) +{ + + while (1) + { + int c = getcFromInputFile (); + if (c == EOF) + return; + else if ((!tokenIsEmpty (token)) && + (isalnum (c) || c == '_')) + tokenPutc (token, c); + else if (isalpha (c) || c == '_') + tokenPutc (token, c); + else + { + ungetcToInputFile (c); + break; + } + } +} + +static void readToken (tokenInfo *const token, void *data) +{ + int c; + bool semi_terminator = false; + + token->type = TOKEN_UNDEFINED; + token->keyword = KEYWORD_NONE; + vStringClear (token->string); + + getNextChar: + /* Skip whitespaces */ + do + { + c = getcFromInputFile (); + } + while (c == ' ' || c== '\t' || c == '\f' || c == '\n'); + + if (c == '/') + { + int c0 = getcFromInputFile (); + + if (c0 == '/') + { + /* line comment */ + while ((c0 = getcFromInputFile ())) + { + if (c0 == EOF) + { + token->type = TOKEN_EOF; + token->lineNumber = getInputLineNumber (); + token->filePosition = getInputFilePosition (); + return; + } + else if (c0 == '\n') + goto getNextChar; + } + + } + else if (c0 == '*') + { + /* block comment */ + int c1; + while ((c1 = getcFromInputFile ())) + { + if (c1 == EOF) + { + token->type = TOKEN_EOF; + token->lineNumber = getInputLineNumber (); + token->filePosition = getInputFilePosition (); + return; + } + else if (c1 == '*') + { + int c2; + lookingForEndOfBlockComment: + c2 = getcFromInputFile (); + if (c2 == EOF) + { + token->type = TOKEN_EOF; + token->lineNumber = getInputLineNumber (); + token->filePosition = getInputFilePosition (); + return; + } + else if (c2 == '/') + goto getNextChar; + else if (c2 == '*') + goto lookingForEndOfBlockComment; + } + } + } + else + ungetcToInputFile (c0); + } + + token->lineNumber = getInputLineNumber (); + token->filePosition = getInputFilePosition (); + switch (c) + { + case EOF: + token->type = TOKEN_EOF; + break; + case '"': + token->type = TOKEN_STRING; + tokenPutc (token, c); + readString (token); + break; + case '@': + token->type = TOKEN_IDENTIFIER; + tokenPutc (token, c); + readIdentifier (token); + break; + case ',': + case '}': + case ']': + case ')': + case '<': + case '>': + case ';': + semi_terminator = true; + case '{': + case '[': + case '(': + token->type = c; + tokenPutc (token, c); + break; + default: + if (isalpha (c) || c == '_') + { + tokenPutc (token, c); + readIdentifier (token); + + token->keyword = resolveKeyword (token->string); + if (token->keyword == KEYWORD_NONE) + token->type = TOKEN_IDENTIFIER; + else + token->type = TOKEN_KEYWORD; + break; + } + else + { + token->type = c; + vStringPut (token->string, c); + break; + } + } + + if (data) + { + vString *collector = data; + if (vStringIsEmpty (collector)) + vStringCat (collector, token->string); + else + { + if (!semi_terminator + && !strchr ("{[(", vStringLast(collector))) + vStringPut(collector, ' '); + vStringCat (collector, token->string); + } + } +} + +static tokenInfo *newValaToken (void) +{ + return newToken (&valaTokenInfoClass); +} + +static int parseStatement (tokenInfo *const token, int parentIndex) +{ + tokenInfo *lastToken = newValaToken (); + bool foundSignature = false; + tagEntryInfo *e = NULL; + int corkIndex = CORK_NIL; + + do + { + tokenCopy (lastToken, token); + tokenRead (token); + if (tokenIsTypeVal (token, '(')) + { + if (tokenIsType (lastToken, KEYWORD)) + tokenSkipOverPair (token); + else + { + corkIndex = makeSimpleTagFromToken (lastToken, K_METHOD, parentIndex); + e = getEntryInCorkQueue (corkIndex); + if (e) + { + vString *signature = vStringNewInit ("("); + foundSignature = tokenSkipOverPairFull (token, signature); + if (foundSignature) + e->extensionFields.signature = vStringDeleteUnwrap (signature); + else + vStringDelete (signature); + } + } + break; + } + } + while (!tokenIsTypeVal (token, ';') && !tokenIsEOF (token)); + + /* Skip the body of method */ + if (foundSignature) + { + while (! (tokenIsTypeVal (token, '{') + || tokenIsTypeVal (token, ';') + || tokenIsEOF (token))) + tokenRead (token); + + if (tokenIsTypeVal (token, '{')) + tokenSkipOverPair (token); + } + + if (e) + e->extensionFields.endLine = token->lineNumber; + + tokenDelete (lastToken); + + return corkIndex; +} + +static void parseEnumBody (tokenInfo *const token, int kindIndex, int corkIndex) +{ + bool s = trianglePairState; + trianglePairState = false; + while (!tokenIsEOF (token)) + { + tokenRead (token); + if (tokenIsType (token, IDENTIFIER)) + { + makeSimpleTagFromToken (token, kindIndex, corkIndex); + tokenType endMakers [] = {',', ';', '}'}; + if (tokenSkipToTypesOverPairs (token, endMakers, ARRAY_SIZE(endMakers))) + { + if (tokenIsTypeVal (token, ',')) + { + tokenRead (token); + if (!tokenIsTypeVal (token, '}')) + { + tokenUnread (token); + continue; + } + } + + if (tokenIsTypeVal (token, '}')) + break; + else if (tokenIsTypeVal (token, ';')) + { + bool t = trianglePairState; + do + { + tokenRead (token); + if (tokenIsTypeVal (token, '}')) + break; + recurseValaTags (token, corkIndex); + } while (!tokenIsEOF (token)); + trianglePairState = t; + break; + } + } + else + break; + } + } + trianglePairState = s; +} + +static void parseEnum (tokenInfo *const token, int kindIndex, int elementKindIndex, int corkIndex) +{ + tokenRead (token); + if (!tokenIsType (token, IDENTIFIER)) + return; /* Unexpected sequence of token */ + + int enumCorkIndex = makeSimpleTagFromToken (token, kindIndex, corkIndex); + + tokenRead (token); + if (!tokenSkipToType (token, '{')) + return; /* Unexpected sequence of token */ + parseEnumBody (token, elementKindIndex, enumCorkIndex); + + tagEntryInfo *e = getEntryInCorkQueue (enumCorkIndex); + if (e) + e->extensionFields.endLine = token->lineNumber; +} + +static bool recurseValaTags (tokenInfo *token, int parentIndex) +{ + bool r = true; + /* Skip attributes */ + if (tokenIsTypeVal (token, '[')) + tokenSkipOverPair (token); + else if (tokenIsKeyword(token, NAMESPACE)) + parseNamespace (token, parentIndex); + else if (tokenIsKeyword(token, INTERFACE)) + parseInterface (token, parentIndex); + else if (tokenIsKeyword(token, CLASS)) + parseClass (token, K_CLASS, parentIndex); + else if (tokenIsKeyword(token, ENUM)) + parseEnum (token, K_ENUM, K_ENUMVALUE, parentIndex); + else if (tokenIsKeyword(token, ERRORDOMAIN)) + parseEnum (token, K_ERRORDOMAIN, K_ERRORCODE, parentIndex); + else if (tokenIsKeyword (token, STRUCT)) + parseClass (token, K_STRUCT, parentIndex); + else if (tokenIsType (token, IDENTIFIER)) + parseStatement (token, parentIndex); + else if (tokenIsKeyword(token, CONSTRUCT)) + { + tokenRead (token); + if (tokenIsTypeVal (token, '{')) + { + /* TODO: we can make an anonymous tag for the constructor. */ + tokenSkipOverPair (token); + } + } + else + r = false; + + return r; +} + +static void parseNamespaceBody (tokenInfo *const token, int parentIndex) +{ + do + { + tokenRead (token); + if (tokenIsTypeVal (token, '}')) + break; + + recurseValaTags (token, parentIndex); + + if (tokenIsTypeVal (token, '{')) + tokenSkipOverPair (token); + + } while (!tokenIsEOF (token)); +} + +static bool readIdentifierExtended (tokenInfo *const resultToken, bool *extended) +{ + bool nextTokenIsIdentifier = false; + tokenInfo *token = newValaToken (); + if (extended) + *extended = false; + + do + { + tokenRead (token); + if (tokenIsTypeVal (token, '.')) + { + tokenPutc (resultToken, '.'); + if (extended) + *extended = true; + } + else if (tokenIsType (token, KEYWORD)) + ; /* Skip keywords */ + else if (tokenIsTypeVal (token, '?')) + ; /* Skip nullable */ + else if (tokenIsTypeVal (token, '*')) + ; /* Skip pointer or indirection */ + else if (tokenIsTypeVal (token, '<')) + /* Skip over generic type parameter. */ + tokenSkipOverPair (token); + else if (tokenIsTypeVal (token, '[')) + /* Skip over array. */ + tokenSkipOverPair (token); + else if (tokenIsType (token, IDENTIFIER)) + { + if (tokenLast (resultToken) == '.') + tokenCat (resultToken, token->string); + else + { + tokenUnread (token); + nextTokenIsIdentifier = true; + break; + } + } + else + { + if (!tokenIsEOF (token)) + tokenUnread (token); + nextTokenIsIdentifier = false; + break; + } + } + while (1); + + tokenDelete (token); + return nextTokenIsIdentifier; +} + +static void parseClassBody (tokenInfo *const token, int classCorkIndex) +{ + char *visiblity = NULL; + tokenInfo *typerefToken = newValaToken (); + tokenInfo *nameToken = newValaToken (); + const char *className = NULL; + + { + tagEntryInfo *e = getEntryInCorkQueue (classCorkIndex); + if (e) + className = e->name; + } + + do + { + bool seen_signal = false; + bool seen_static = false; + tokenRead (token); + if (tokenIsTypeVal (token, '}')) + break; + + if (tokenIsKeyword(token, PUBLIC) || tokenIsKeyword (token, PROTECTED) || + tokenIsKeyword (token, PRIVATE) || tokenIsKeyword (token, INTERNAL)) + { + visiblity = eStrdup (tokenString (token)); + tokenRead (token); + } + + while (true) + { + if (tokenIsKeyword(token, STATIC)) + { + seen_static = true; + tokenRead (token); + } + else if (tokenIsKeyword(token, SIGNAL)) + { + seen_signal = true; + tokenRead (token); + } + else if (tokenIsKeyword(token, CONST) + || tokenIsKeyword(token, NEW)) + { + /* TODO: we can record "const" to "properties:" field. */ + tokenRead (token); + } + else + break; + } + + if (tokenIsKeyword(token, CLASS) + || tokenIsKeyword(token, CONSTRUCT)) + { + recurseValaTags (token, classCorkIndex); + if (visiblity) + { + eFree (visiblity); + visiblity = NULL; + } + continue; + } + + if (tokenIsType (token, IDENTIFIER) + || tokenIsType (token, KEYWORD)) + tokenCopy (typerefToken, token); + else + { + if (visiblity) + eFree (visiblity); + break; /* Unexpected sequence to token */ + } + + bool typerefIsClass; + readIdentifierExtended (typerefToken, &typerefIsClass); + + bool nameFound = false; + tokenRead (token); + if (tokenIsType (token, IDENTIFIER)) + { + tokenCopy (nameToken, token); + nameFound = true; + tokenRead (token); + } + + int kind = KIND_GHOST_INDEX; + int methodIndex = CORK_NIL; + bool is_name_constructor = false; + if (tokenIsTypeVal (token, '(')) + { + if (nameFound) + { + /* Method */ + tokenUnread(token); + tokenCopy (token, nameToken); + methodIndex = parseStatement (token, classCorkIndex); + tagEntryInfo *e = getEntryInCorkQueue (methodIndex); + if (e && e->kindIndex == K_METHOD) + { + if (seen_signal) + e->kindIndex = K_SIGNAL; + kind = e->kindIndex; + } + } + else if (strcmp (vStringValue (typerefToken->string), className) == 0) + { + /* Constructor */ + tokenUnread(token); + tokenCopy (token, typerefToken); + is_name_constructor = true; + methodIndex = parseStatement (token, classCorkIndex); + tagEntryInfo *e = getEntryInCorkQueue (methodIndex); + if (e && e->kindIndex == K_METHOD) + kind = e->kindIndex; + } + else + { + tokenSkipOverPair (token); + tokenRead (token); + } + } + else if (tokenIsTypeVal (token, ';') + || tokenIsTypeVal (token, '=')) + { + kind = K_FIELD; + if (tokenIsTypeVal (token, '=')) + { + bool s = trianglePairState; + tokenSkipToTypeOverPairs (token, ';'); + trianglePairState = s; + } + } + else if (tokenIsTypeVal (token, '{')) + kind = K_PROP; + else + break; /* Unexpected sequence of token */ + + int memberCorkIndex = methodIndex == CORK_NIL + ? makeSimpleTagFromToken (nameToken, kind, classCorkIndex) + : methodIndex; + tagEntryInfo *entry = getEntryInCorkQueue (memberCorkIndex); + + /* Fill access field. */ + entry->extensionFields.access = visiblity; + visiblity = NULL; + if (!is_name_constructor) + { + /* Fill typeref field. */ + entry->extensionFields.typeRef [0] = eStrdup ( + typerefIsClass? + /* '.' is included in typeref name. Can I expect it as a class? + */ + "class" + :tokenIsType (typerefToken, KEYWORD)? + /* "typename" is choice in C++ parser. However, "builtin" may be + * better. See #862. This should be fixed in ctags-6.0.0. */ + "typename" + : + /* Till we implement symbol table, we cannot resolve this. + * ctags-7.0.0. */ + "unknown"); + entry->extensionFields.typeRef [1] = vStringStrdup(typerefToken->string); + } + /* Fill prototypes field. */ + if (seen_static) + attachParserField(entry, ValaFields[F_PROPERTIES].ftype, "static"); + + if (kind == K_PROP) + tokenSkipOverPair (token); + if (kind != K_METHOD && kind != K_SIGNAL) + entry->extensionFields.endLine = token->lineNumber; + } while (!tokenIsEOF (token)); + + if (visiblity) + eFree (visiblity); + tokenDelete (typerefToken); + tokenDelete (nameToken); +} + +static void parseNamespace (tokenInfo *const token, int parentIndex) +{ + + tokenRead (token); + if (!tokenIsType (token, IDENTIFIER)) + return; /* Unexpected sequence of token */ + + int namespaceCorkIndex = makeSimpleTagFromToken (token, K_NAMESPACE, parentIndex); + + tokenRead (token); + if (!tokenSkipToType (token, '{')) + return; /* Unexpected sequence of token */ + + parseNamespaceBody (token, namespaceCorkIndex); + tagEntryInfo *e = getEntryInCorkQueue (namespaceCorkIndex); + if (e) + e->extensionFields.endLine = token->lineNumber; +} + +static void parseInterface (tokenInfo *const token, int parentIndex) +{ + + tokenRead (token); + if (!tokenIsType (token, IDENTIFIER)) + return; /* Unexpected sequence of token */ + + int interfaceCorkIndex = makeSimpleTagFromToken (token, K_INTERFACE, parentIndex); + + tokenRead (token); + if (!tokenSkipToType (token, '{')) + return; /* Unexpected sequence of token */ + + parseClassBody (token, interfaceCorkIndex); /* Should we have a custom parser? */ + tagEntryInfo *e = getEntryInCorkQueue (interfaceCorkIndex); + if (e) + e->extensionFields.endLine = token->lineNumber; +} + +static void parseInheritanceList (tokenInfo *const token, int classIndex) +{ + vString *list = vStringNew (); + + do + { + tokenRead (token); + if (!tokenIsType (token, IDENTIFIER)) + break; /* Unexpected sequence of token */ + readIdentifierExtended (token, NULL); + vStringCat (list, token->string); + + tokenRead (token); + if (tokenIsTypeVal (token, ',')) + vStringPut (list, ','); + else if (tokenIsTypeVal (token, '{')) + { + tagEntryInfo *e = getEntryInCorkQueue (classIndex); + if (e) + { + e->extensionFields.inheritance = vStringDeleteUnwrap (list); + list = NULL; + } + break; + } + else + break; /* Unexpected sequence of token or EOF */ + } while (1); + + vStringDelete (list); /* NULL is acceptable */ +} + +static void parseClass (tokenInfo *const token, int kindIndex, int parentIndex) +{ + tokenRead (token); + if (!tokenIsType (token, IDENTIFIER)) + return; /* Unexpected sequence of token */ + readIdentifierExtended (token, NULL); + + int classCorkIndex = makeSimpleTagFromToken (token, kindIndex, parentIndex); + + /* Parse the class definition. */ + tokenRead (token); + if (tokenIsTypeVal (token, ':')) + parseInheritanceList (token, classCorkIndex); + + if (!tokenSkipToType (token, '{')) + return; /* Unexpected sequence of token */ + + parseClassBody (token, classCorkIndex); + tagEntryInfo *e = getEntryInCorkQueue (classCorkIndex); + if (e) + e->extensionFields.endLine = token->lineNumber; +} + +static void findValaTags (void) +{ + tokenInfo *const token = newValaToken (); + do + { + tokenRead (token); + recurseValaTags (token, CORK_NIL); + } + while (!tokenIsEOF (token)); + + tokenDelete (token); + flashTokenBacklog (&valaTokenInfoClass); +} + +static void initialize (const langType language) +{ + addKeywordGroup (&valaBuiltInKeywordGroup, language); +} + +extern parserDefinition* ValaParser (void) +{ + static const char *const extensions [] = { "vala", NULL }; + + parserDefinition* def = parserNew ("Vala"); + def->kindTable = ValaKinds; + def->kindCount = ARRAY_SIZE (ValaKinds); + def->extensions = extensions; + def->keywordTable = ValaKeywordTable; + def->keywordCount = ARRAY_SIZE (ValaKeywordTable); + def->fieldTable = ValaFields; + def->fieldCount = ARRAY_SIZE (ValaFields); + def->useCork = true; + def->requestAutomaticFQTag = true; + + def->initialize = initialize, + def->parser = findValaTags; + return def; +} diff --git a/source.mak b/source.mak index 2266f84e19..fd834c28e3 100644 --- a/source.mak +++ b/source.mak @@ -414,6 +414,7 @@ PARSER_SRCS = \ parsers/ttcn.c \ parsers/txt2tags.c \ parsers/typescript.c \ + parsers/vala.c \ parsers/vera.c \ parsers/verilog.c \ parsers/vhdl.c \ diff --git a/win32/ctags_vs2013.vcxproj b/win32/ctags_vs2013.vcxproj index 8e2fb01d6b..7df42e62c4 100644 --- a/win32/ctags_vs2013.vcxproj +++ b/win32/ctags_vs2013.vcxproj @@ -367,6 +367,7 @@ + diff --git a/win32/ctags_vs2013.vcxproj.filters b/win32/ctags_vs2013.vcxproj.filters index 3a327be697..794fc55df3 100644 --- a/win32/ctags_vs2013.vcxproj.filters +++ b/win32/ctags_vs2013.vcxproj.filters @@ -624,6 +624,9 @@ Source Files\parsers + + Source Files\parsers + Source Files\parsers