Add 'vendored_parsers/tree-sitter-sfapex/' from commit 'a768c956b6aee72ffebb5df7f7c0b3702eaa2fbd'

git-subtree-dir: vendored_parsers/tree-sitter-sfapex
git-subtree-mainline: 1d32b477c1
git-subtree-split: a768c956b6
pull/579/head
Rodolphe Blancho 2023-10-05 08:37:36 +07:00
commit b818b47091
160 changed files with 171972 additions and 0 deletions

@ -0,0 +1,64 @@
# https://github.com/TryGhost/node-sqlite3/blob/master/.github/workflows/ci.yml
name: CI
on:
workflow_dispatch:
push:
tags:
- "*"
env:
FORCE_COLOR: 1
jobs:
build:
runs-on: ${{ matrix.os }}
strategy:
fail-fast: false
matrix:
os:
- macos-latest
- ubuntu-latest
- windows-latest
host:
- x64
target:
- x64
node:
- 14
- 16
- 18
# include:
# - os: macos-m1
# node: 16
# host: arm64
# target: arm64
name: ${{ matrix.os }} (node=${{ matrix.node }}, host=${{ matrix.host }}, target=${{ matrix.target }})
steps:
- uses: actions/checkout@v3
- uses: actions/setup-node@v3
with:
node-version: ${{ matrix.node }}
architecture: ${{ matrix.host }}
- name: Npm install tree-sitter
run: |
npm i tree-sitter
- name: Tree-sitter build
run: |
npm run build
- name: Npm install/compile
run: |
npm install
- name: Configure build
run: npx node-pre-gyp configure --target_arch=${{ matrix.target }}
- name: Build binaries
run: npx node-pre-gyp build --target_arch=${{ matrix.target }}
- name: Package prebuilt binaries
run: npx node-pre-gyp package --target_arch=${{ matrix.target }}
- name: Upload binaries to GitHub Release
run: node ./scripts/ghPublish.mjs
if: startsWith(github.ref, 'refs/tags/')
env:
NODE_PRE_GYP_GITHUB_TOKEN: ${{ github.token }}

@ -0,0 +1,37 @@
name: Test full
on:
push:
branches:
- main
pull_request:
branches:
- main
jobs:
build:
runs-on: ${{ matrix.os }}
strategy:
fail-fast: false
matrix:
os: [ubuntu-latest, macos-latest, windows-latest]
steps:
- uses: actions/checkout@v3
- name: Use Node.js
uses: actions/setup-node@v3
with:
node-version: 16
- name: Npm install tree-sitter
run: |
npm i tree-sitter
- name: Tree-sitter build
run: |
npm run build
- name: Npm install/compile
run: |
npm install
- name: Unit tests
run: |
npm test

@ -0,0 +1,22 @@
Cargo.lock
node_modules
.node-version
target
build
*.log
/test.ts
examples/desktop
examples/redux
examples/vscode
log.html
# These files would be generated by 'tree-sitter generate' with the default
# settings. We don't want them because there's already a copy at the root.
# discarding generated files as they will be rebuilt as needed (will be added back by installer)
*.wasm
/*/Cargo.toml
/*/binding.gyp
/*/bindings
**/parser.exp
**/parser.lib
**/parser.obj

@ -0,0 +1,26 @@
[package]
name = "tree-sitter-apex"
description = "apex grammar for the tree-sitter parsing library"
version = "0.0.1"
keywords = ["incremental", "parsing", "apex"]
categories = ["parsing", "text-editors"]
repository = "https://github.com/aheber/tree-sitter-apex"
edition = "2018"
license = "MIT"
build = "bindings/rust/build.rs"
include = [
"bindings/rust/*",
"grammar.js",
"queries/*",
"src/*",
]
[lib]
path = "bindings/rust/lib.rs"
[dependencies]
tree-sitter = "~0.20"
[build-dependencies]
cc = "1.0"

@ -0,0 +1,21 @@
The MIT License (MIT)
Copyright (c) 2012 Anthony Heber
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

@ -0,0 +1,60 @@
# tree-sitter-sfapex
Salesforce grammars for [tree-sitter](https://github.com/tree-sitter/tree-sitter), including Apex, SOQL, and SOSL languages.
Try it out using our [playground](https://aheber.github.io/tree-sitter-sfapex/playground/)
If you are a Neo-vim user, the parsers and syntax highlights are part of nvim-treesitter
plugin already, [guidance](nvim-treesitter-setup.md).
## Status
Most of the parsers are built and tested on large corpus of Apex, I still intend to write automated tests that parse large Apex libraries as part of evaluating the grammar.
### Apex
- [x] grammar
- [x] grammar tests
- [x] highlighting queries
- [x] highlighting tests
- [x] tags queries
- [x] tags tests (could use more)
- [x] locals queries
- [x] locals tests (using highlighting)
### Anonymous Apex
- [ ] grammar
- [ ] grammar tests
- [ ] highlighting queries
- [ ] highlighting tests
- [ ] tags queries
- [ ] tags tests (could use more)
- [ ] locals queries
- [ ] locals tests (using highlighting)
_This won't be difficult, I just haven't tackled it yet, will largely reuse the Apex grammar with some different construction rules._
### SOQL
- [x] grammar
- [x] grammar tests
- [x] highlighting queries
- [x] highlighting tests
### SOSL
- [x] grammar
- [x] grammar tests
- [x] highlighting queries
- [x] highlighting tests
(not sure tags and locals are relevant to query grammars)
## Questions/Issues
Please open an issue on this repo and we'll work through it.
## Contributing
Still figuring this out. By far the most useful contributions would be tests, if you have a scenario that doesn't work you can just provide the example or open a PR with a new failing test and I can figure out what to do about it.

@ -0,0 +1,931 @@
// Adapted from https://github.com/tree-sitter/tree-sitter-java/blob/master/grammar.js
const {
ci,
commaJoined,
commaJoined1,
joined,
} = require("../common/common.js");
const LANG = "apex";
// SOSL includes SOQL as a sub-type
const soslGrammar = require("../common/sosl-grammar.js")(LANG);
const DIGITS = token(joined(/_+/, /[0-9]+/));
const PREC = {
// https://introcs.cs.princeton.edu/java/11precedence/
COMMENT: 0, // // /* */
ASSIGN: 1, // = += -= *= /= %= &= ^= |= <<= >>= >>>=
SWITCH_EXP: 1, // always prefer to parse switch as expression over statement
DECL: 2,
ELEMENT_VAL: 2,
TERNARY: 3, // ?:
OR: 4, // ||
AND: 5, // &&
BIT_OR: 6, // |
BIT_XOR: 7, // ^
BIT_AND: 8, // &
EQUALITY: 9, // == != <>
GENERIC: 10,
REL: 10, // < <= > >= instanceof
SHIFT: 11, // << >> >>>
ADD: 12, // + -
MULT: 13, // * / %
CAST: 14, // (Type)
OBJ_INST: 14, // new
UNARY: 15, // ++a --a a++ a-- + - ! ~
ARRAY: 16, // [Index]
OBJ_ACCESS: 16, // .
PARENS: 16, // (Expression)
};
module.exports = grammar({
name: LANG,
extras: ($) => [$.line_comment, $.block_comment, /\s/],
supertypes: ($) => [
$.expression,
$.declaration,
$.statement,
$.primary_expression,
$._literal,
$._type,
$._simple_type,
$._unannotated_type,
$.comment,
],
inline: ($) => [
$._name,
$._simple_type,
$._class_body_declaration,
$._variable_initializer,
],
word: ($) => $.identifier,
conflicts: ($) => [
[$._unannotated_type, $.primary_expression],
[$._unannotated_type, $.primary_expression, $.scoped_type_identifier],
[$._unannotated_type, $.scoped_type_identifier],
[$._unannotated_type, $.generic_type],
[$._unannotated_type, $.type_parameter],
[$.generic_type, $.primary_expression],
[$._property_navigation, $.explicit_constructor_invocation],
[$.field_access, $.method_invocation, $.expression],
[$.map_initializer, $.array_initializer],
[$.function_name, $.count_expression],
[$.switch_label, $.primary_expression],
],
rules: {
//////////////////////////
parser_output: ($) => repeat($.statement),
// Expressions
expression: ($) =>
choice(
$.assignment_expression,
$.binary_expression,
$.instanceof_expression,
$.ternary_expression,
$.update_expression,
$.primary_expression,
$.unary_expression,
$.cast_expression,
$.dml_expression,
prec(PREC.SWITCH_EXP, $.switch_expression)
),
soql_query: ($) => seq($.soql_query_body),
sosl_query: ($) => seq($.sosl_query_body),
query_expression: ($) => seq("[", choice($.soql_query, $.sosl_query), "]"),
dml_expression: ($) =>
prec.right(
choice(
seq($.dml_type, $.expression),
seq(
alias(ci("upsert"), $.dml_type),
$.expression,
optional($._unannotated_type)
),
seq(alias(ci("merge"), $.dml_type), $.expression, " ", $.expression)
)
),
dml_type: ($) =>
choice(ci("insert"), ci("update"), ci("delete"), ci("undelete")),
cast_expression: ($) =>
prec(
PREC.CAST,
seq("(", field("type", $._type), ")", field("value", $.expression))
),
assignment_expression: ($) =>
prec.right(
PREC.ASSIGN,
seq(
field("left", choice($.identifier, $.field_access, $.array_access)),
field(
"operator",
alias(
choice(
"=",
"+=",
"-=",
"*=",
"/=",
"&=",
"|=",
"^=",
"%=",
"<<=",
">>=",
">>>="
),
$.assignment_operator
)
),
field("right", $.expression)
)
),
binary_expression: ($) =>
choice(
...[
[">", PREC.REL],
["<", PREC.REL],
[">=", PREC.REL],
["<=", PREC.REL],
["==", PREC.EQUALITY],
["===", PREC.EQUALITY],
["!=", PREC.EQUALITY],
["<>", PREC.EQUALITY],
["!==", PREC.EQUALITY],
["&&", PREC.AND],
["||", PREC.OR],
["+", PREC.ADD],
["-", PREC.ADD],
["*", PREC.MULT],
["/", PREC.MULT],
["&", PREC.BIT_AND],
["|", PREC.BIT_OR],
["^", PREC.BIT_XOR],
["%", PREC.MULT],
["<<", PREC.SHIFT],
[">>", PREC.SHIFT],
[">>>", PREC.SHIFT],
].map(([operator, precedence]) =>
prec.left(
precedence,
seq(
field("left", $.expression),
field("operator", operator),
field("right", $.expression)
)
)
)
),
instanceof_expression: ($) =>
prec(
PREC.REL,
seq(
field("left", $.expression),
ci("instanceof"),
field("right", $._type)
)
),
inferred_parameters: ($) => seq("(", commaJoined1($.identifier), ")"),
ternary_expression: ($) =>
prec.right(
PREC.TERNARY,
seq(
field("condition", $.expression),
"?",
field("consequence", $.expression),
":",
field("alternative", $.expression)
)
),
unary_expression: ($) =>
choice(
...[
["+", PREC.UNARY],
["-", PREC.UNARY],
["!", PREC.UNARY],
["~", PREC.UNARY],
].map(([operator, precedence]) =>
prec.left(
precedence,
seq(field("operator", operator), field("operand", $.expression))
)
)
),
update_expression: ($) =>
prec.left(
PREC.UNARY,
choice(
// Post (in|de)crement is evaluated before pre (in|de)crement
seq($.expression, "++"),
seq($.expression, "--"),
seq("++", $.expression),
seq("--", $.expression)
)
),
primary_expression: ($) =>
choice(
$._literal,
$.class_literal,
$.this,
$.identifier,
$.parenthesized_expression,
$.object_creation_expression,
$.field_access,
$.array_access,
$.method_invocation,
$.array_creation_expression,
$.map_creation_expression,
$.query_expression
),
array_creation_expression: ($) =>
prec.right(
seq(
ci("new"),
field("type", $._simple_type),
choice(
seq(
field("dimensions", repeat1($.dimensions_expr)),
field("dimensions", optional($.dimensions))
),
seq(
field("dimensions", $.dimensions),
field("value", $.array_initializer)
),
seq(field("value", $.array_initializer))
)
)
),
map_creation_expression: ($) =>
prec.right(
seq(
ci("new"),
field("type", $._simple_type),
seq(field("value", $.map_initializer))
)
),
dimensions_expr: ($) => seq("[", $.expression, "]"),
parenthesized_expression: ($) => seq("(", $.expression, ")"),
class_literal: ($) => seq($._unannotated_type, ".", ci("class")),
object_creation_expression: ($) =>
$._unqualified_object_creation_expression,
_unqualified_object_creation_expression: ($) =>
prec.right(
seq(
ci("new"),
field("type_arguments", optional($.type_arguments)),
field("type", $._simple_type),
field("arguments", $.argument_list),
optional($.class_body)
)
),
field_access: ($) =>
seq(
field("object", choice($.primary_expression, $.super)),
optional(seq($._property_navigation, $.super)),
$._property_navigation,
field("field", choice($.identifier, $.this))
),
_property_navigation: ($) => seq(optional("?"), "."),
array_access: ($) =>
seq(
field("array", $.primary_expression),
"[",
field("index", $.expression),
"]"
),
method_invocation: ($) =>
seq(
choice(
field("name", $.identifier),
seq(
field("object", choice($.primary_expression, $.super)),
$._property_navigation,
optional(seq($.super, $._property_navigation)),
field("type_arguments", optional($.type_arguments)),
field("name", $.identifier)
)
),
field("arguments", $.argument_list)
),
argument_list: ($) => seq("(", commaJoined($.expression), ")"),
type_arguments: ($) => seq("<", commaJoined($._type), ">"),
dimensions: ($) => prec.right(repeat1(seq("[", "]"))),
switch_expression: ($) =>
seq(
ci("switch"),
ci("on"),
field("condition", $.expression),
field("body", $.switch_block)
),
switch_block: ($) => seq("{", repeat1($.switch_rule), "}"),
switch_rule: ($) => seq($.switch_label, $.block),
switch_label: ($) =>
seq(
ci("when"),
choice(
// SObject type var syntax
prec.right(
commaJoined1(seq(optional($._unannotated_type), $.identifier))
),
commaJoined1($.expression),
ci("else")
)
),
// Statements
statement: ($) =>
choice(
$.declaration,
$.expression_statement,
$.labeled_statement,
$.if_statement,
$.while_statement,
$.for_statement,
$.enhanced_for_statement,
$.block,
";",
$.do_statement,
$.break_statement,
$.continue_statement,
$.return_statement,
$.switch_expression, //switch statements and expressions are identical
$.local_variable_declaration,
$.throw_statement,
$.try_statement,
$.run_as_statement
),
block: ($) => seq("{", repeat($.statement), "}"),
expression_statement: ($) => seq($.expression, ";"),
labeled_statement: ($) => seq($.identifier, ":", $.statement),
do_statement: ($) =>
seq(
ci("do"),
field("body", $.statement),
ci("while"),
field("condition", $.parenthesized_expression),
";"
),
break_statement: ($) => seq(ci("break"), optional($.identifier), ";"),
continue_statement: ($) => seq(ci("continue"), optional($.identifier), ";"),
return_statement: ($) => seq(ci("return"), optional($.expression), ";"),
throw_statement: ($) => seq(ci("throw"), $.expression, ";"),
try_statement: ($) =>
seq(
ci("try"),
field("body", $.block),
choice(
repeat1($.catch_clause),
seq(repeat($.catch_clause), $.finally_clause)
)
),
catch_clause: ($) =>
seq(
ci("catch"),
"(",
$.catch_formal_parameter,
")",
field("body", $.block)
),
catch_formal_parameter: ($) =>
seq(
optional($.modifiers),
$._unannotated_type,
$._variable_declarator_id
),
finally_clause: ($) => seq(ci("finally"), $.block),
if_statement: ($) =>
prec.right(
seq(
ci("if"),
field("condition", $.parenthesized_expression),
field("consequence", $.statement),
optional(seq(ci("else"), field("alternative", $.statement)))
)
),
while_statement: ($) =>
seq(
ci("while"),
field("condition", $.parenthesized_expression),
field("body", $.statement)
),
for_statement: ($) =>
seq(
ci("for"),
"(",
choice(
field("init", $.local_variable_declaration),
seq(commaJoined(field("init", $.expression)), ";")
),
field("condition", optional($.expression)),
";",
commaJoined(field("update", $.expression)),
")",
field("body", $.statement)
),
enhanced_for_statement: ($) =>
seq(
ci("for"),
"(",
optional($.modifiers),
field("type", $._unannotated_type),
$._variable_declarator_id,
":",
field("value", $.expression),
")",
field("body", $.statement)
),
run_as_statement: ($) =>
// TODO: there might be a better generic way to express this
seq(
ci("System.runAs"),
field("user", $.parenthesized_expression),
$.block
),
annotation: ($) =>
seq(
"@",
field("name", $._name),
optional(field("arguments", $.annotation_argument_list))
),
annotation_argument_list: ($) =>
seq(
"(",
choice(
field("value", $._element_value),
joined(optional(","), $.annotation_key_value)
),
")"
),
annotation_key_value: ($) =>
seq(
field("key", $.identifier),
alias("=", $.assignment_operator),
field("value", $._element_value)
),
_element_value: ($) =>
prec(
PREC.ELEMENT_VAL,
choice($.expression, $.element_value_array_initializer, $.annotation)
),
element_value_array_initializer: ($) =>
seq("{", commaJoined($._element_value), optional(","), "}"),
// Declarations
declaration: ($) =>
prec(
PREC.DECL,
choice(
$.class_declaration,
$.trigger_declaration,
$.interface_declaration,
$.enum_declaration,
$.method_declaration
)
),
enum_declaration: ($) =>
seq(
optional($.modifiers),
ci("enum"),
field("name", $.identifier),
field("interfaces", optional($.interfaces)),
field("body", $.enum_body)
),
enum_body: ($) => seq("{", commaJoined($.enum_constant), "}"),
enum_constant: ($) =>
seq(optional($.modifiers), field("name", $.identifier)),
class_declaration: ($) =>
seq(
optional($.modifiers),
ci("class"),
field("name", $.identifier),
optional(field("type_parameters", $.type_parameters)),
optional(field("superclass", $.superclass)),
optional(field("interfaces", $.interfaces)),
field("body", $.class_body)
),
trigger_declaration: ($) =>
seq(
ci("trigger"),
field("name", $.identifier),
ci("on"),
field("object", $.identifier),
"(",
field("events", commaJoined1($.trigger_event)),
")",
field("body", $.trigger_body)
),
trigger_event: ($) =>
choice(
seq(ci("before"), ci("insert")),
seq(ci("before"), ci("update")),
seq(ci("before"), ci("delete")),
seq(ci("after"), ci("insert")),
seq(ci("after"), ci("update")),
seq(ci("after"), ci("delete")),
seq(ci("after"), ci("undelete"))
),
trigger_body: ($) => $.block,
modifiers: ($) => repeat1(choice($.annotation, $.modifier)),
modifier: ($) =>
choice(
ci("global"),
ci("public"),
ci("testMethod"),
ci("protected"),
ci("override"),
ci("private"),
ci("virtual"),
ci("abstract"),
ci("static"),
ci("final"),
ci("transient"),
ci("with sharing"),
ci("without sharing"),
ci("inherited sharing")
),
type_parameters: ($) => seq("<", commaJoined1($.type_parameter), ">"),
type_parameter: ($) =>
seq(
repeat($.annotation),
alias($.identifier, $.type_identifier),
optional($.type_bound)
),
// TODO: do we need this?
type_bound: ($) => seq(ci("extends"), $._type, repeat(seq("&", $._type))),
superclass: ($) => seq(ci("extends"), $._type),
interfaces: ($) => seq(ci("implements"), $.type_list),
type_list: ($) => seq($._type, repeat(seq(",", $._type))),
class_body: ($) => seq("{", repeat($._class_body_declaration), "}"),
_class_body_declaration: ($) =>
choice(
$.field_declaration,
$.method_declaration,
$.class_declaration,
$.interface_declaration,
$.enum_declaration,
$.block,
$.static_initializer,
$.constructor_declaration,
";"
),
static_initializer: ($) => seq(ci("static"), $.block),
constructor_declaration: ($) =>
seq(
optional($.modifiers),
$._constructor_declarator,
field("body", $.constructor_body)
),
_constructor_declarator: ($) =>
seq(
field("type_parameters", optional($.type_parameters)),
field("name", $.identifier),
field("parameters", $.formal_parameters)
),
constructor_body: ($) =>
seq(
"{",
optional($.explicit_constructor_invocation),
repeat($.statement),
"}"
),
explicit_constructor_invocation: ($) =>
seq(
choice(
seq(
field("type_arguments", optional($.type_arguments)),
field("constructor", choice($.this, $.super))
),
seq(
field("object", choice($.primary_expression)),
".",
field("type_arguments", optional($.type_arguments)),
field("constructor", $.super)
)
),
field("arguments", $.argument_list),
";"
),
_name: ($) => choice($.identifier, $.scoped_identifier),
scoped_identifier: ($) =>
seq(field("scope", $._name), ".", field("name", $.identifier)),
field_declaration: ($) =>
seq(
optional($.modifiers),
field("type", $._unannotated_type),
$._variable_declarator_list,
choice($.accessor_list, ";")
),
_default_value: ($) => seq("default", field("value", $._element_value)),
interface_declaration: ($) =>
seq(
optional($.modifiers),
ci("interface"),
field("name", $.identifier),
field("type_parameters", optional($.type_parameters)),
optional($.extends_interfaces),
field("body", $.interface_body)
),
extends_interfaces: ($) => seq(ci("extends"), $.type_list),
interface_body: ($) =>
seq(
"{",
repeat(
choice(
$.constant_declaration,
$.enum_declaration,
$.method_declaration,
$.class_declaration,
$.interface_declaration,
";"
)
),
"}"
),
constant_declaration: ($) =>
seq(
optional($.modifiers),
field("type", $._unannotated_type),
$._variable_declarator_list,
";"
),
_variable_declarator_list: ($) =>
commaJoined1(field("declarator", $.variable_declarator)),
variable_declarator: ($) =>
seq(
$._variable_declarator_id,
optional(
seq(
alias("=", $.assignment_operator),
field("value", $._variable_initializer)
)
)
),
_variable_declarator_id: ($) =>
seq(
field("name", $.identifier),
field("dimensions", optional($.dimensions))
),
_variable_initializer: ($) => choice($.expression, $.array_initializer),
_map_initializer: ($) => seq($.expression, "=>", $.expression),
array_initializer: ($) =>
seq("{", commaJoined($._variable_initializer), "}"),
map_initializer: ($) => seq("{", commaJoined($._map_initializer), "}"),
// Types
_type: ($) => choice($._unannotated_type, $.annotated_type),
_unannotated_type: ($) => choice($._simple_type, $.array_type),
void_type: ($) => ci("void"),
_simple_type: ($) =>
choice(
$.void_type,
$.boolean_type,
alias($.identifier, $.type_identifier),
$.scoped_type_identifier,
$.generic_type
),
annotated_type: ($) => seq(repeat1($.annotation), $._unannotated_type),
scoped_type_identifier: ($) =>
seq(
choice(
alias($.identifier, $.type_identifier),
$.scoped_type_identifier,
$.generic_type
),
".",
repeat($.annotation),
alias($.identifier, $.type_identifier)
),
generic_type: ($) =>
prec.dynamic(
PREC.GENERIC,
seq(
choice(
alias($.identifier, $.type_identifier),
$.scoped_type_identifier
),
$.type_arguments
)
),
array_type: ($) =>
seq(
field("element", $._unannotated_type),
field("dimensions", $.dimensions)
),
boolean_type: ($) => "boolean",
_method_header: ($) =>
seq(
optional(
seq(field("type_parameters", $.type_parameters), repeat($.annotation))
),
field("type", $._unannotated_type),
$._method_declarator
),
_method_declarator: ($) =>
seq(
field("name", $.identifier),
field("parameters", $.formal_parameters),
field("dimensions", optional($.dimensions))
),
formal_parameters: ($) => seq("(", commaJoined($.formal_parameter), ")"),
formal_parameter: ($) =>
seq(
optional($.modifiers),
field("type", $._unannotated_type),
$._variable_declarator_id
),
local_variable_declaration: ($) =>
seq(
optional($.modifiers),
field("type", $._unannotated_type),
$._variable_declarator_list,
";"
),
method_declaration: ($) =>
seq(
optional($.modifiers),
$._method_header,
choice(field("body", $.block), ";")
),
this: ($) => ci("this"),
super: ($) => ci("super"),
// http://stackoverflow.com/questions/13014947/regex-to-match-a-c-style-multiline-comment/36328890#36328890
comment: ($) => choice($.line_comment, $.block_comment),
line_comment: ($) => token(prec(PREC.COMMENT, seq("//", /[^\n]*/))),
block_comment: ($) =>
token(prec(PREC.COMMENT, seq("/*", /[^*]*\*+([^/*][^*]*\*+)*/, "/"))),
accessor_list: ($) => seq("{", repeat1($.accessor_declaration), "}"),
accessor_declaration: ($) =>
seq(
optional($.modifiers),
choice(ci("get"), ci("set")),
choice($.block, ";")
),
...soslGrammar.rules,
// https://docs.oracle.com/javase/specs/jls/se8/html/jls-3.html#jls-IdentifierChars
identifier: ($) => /[\p{L}_$][\p{L}\p{Nd}_$]*/,
// Literals
_literal: ($) =>
choice(
$.int,
$.decimal_floating_point_literal,
$.boolean,
$.string_literal,
$.null_literal
),
int: ($) => token(seq(DIGITS, optional(choice("l", "L")))),
decimal_floating_point_literal: ($) =>
token(
choice(
seq(
DIGITS,
".",
optional(DIGITS),
optional(seq(/[eE]/, optional(choice("-", "+")), DIGITS)),
optional(/[fFdD]/)
),
seq(
".",
DIGITS,
optional(seq(/[eE]/, optional(choice("-", "+")), DIGITS)),
optional(/[fFdD]/)
),
seq(
DIGITS,
/[eEpP]/,
optional(choice("-", "+")),
DIGITS,
optional(/[fFdD]/)
),
seq(
DIGITS,
optional(seq(/[eE]/, optional(choice("-", "+")), DIGITS)),
/[fFdD]/
)
)
),
string_literal: ($) => /'(\\[nNrRtTbBfFuU"'_%\\]|[^\\'])*'/,
},
});

@ -0,0 +1,21 @@
{
"main": "../bindings/node/apex",
"tree-sitter": [
{
"scope": "source.apex",
"file-types": [
"cls",
"trigger",
"apex"
],
"highlights": [
"../soql/queries/highlights.scm",
"../sosl/queries/highlights.scm",
"queries/highlights.scm"
],
"tags": [
"queries/tags.scm"
]
}
]
}

@ -0,0 +1,302 @@
;; attempting to match concepts represented here:
;; https://code.visualstudio.com/api/language-extensions/semantic-highlight-guide
[
"["
"]"
"{"
"}"
"?"
";"
] @punctuation
;; Methods
(method_declaration
name: (identifier) @method)
(method_declaration
type: (type_identifier) @type)
(method_invocation
name: (identifier) @method)
(argument_list
(identifier) @variable)
(super) @function.defaultLibrary
(explicit_constructor_invocation
arguments: (argument_list
(identifier) @variable ))
;; Annotations
(annotation
name: (identifier) @decorator)
"@" @operator
(annotation_key_value
(identifier) @variable)
;; Types
(interface_declaration
name: (identifier) @interface)
(class_declaration
name: (identifier) @class)
(class_declaration
(superclass) @class)
(enum_declaration
name: (identifier) @enum)
(enum_constant
name: (identifier) @enumMember)
(interfaces
(type_list
(type_identifier) @interface ))
(local_variable_declaration
(type_identifier) @type )
( expression_statement (_ (identifier)) @variable)
(type_arguments "<" @punctuation)
(type_arguments ">" @punctuation)
; (identifier) @variable
((field_access
object: (identifier) @type)) ;; don't know what type of thing it is
(generic_type
(type_identifier) @type)
(type_arguments (type_identifier) @type)
(field_access
field: (identifier) @property)
((scoped_identifier
scope: (identifier) @type)
(#match? @type "^[A-Z]"))
((method_invocation
object: (identifier) @type)
(#match? @type "^[A-Z]"))
(field_declaration
type: (type_identifier) @type)
(method_declaration
(formal_parameters
(formal_parameter
name: (identifier) @parameter)))
(formal_parameter
type: (type_identifier) @type
(identifier) @variable)
(enhanced_for_statement
type: (type_identifier) @type
name: (identifier) @variable )
(enhanced_for_statement
value: (identifier) @variable)
(enhanced_for_statement
name: (identifier) @variable)
(object_creation_expression
type: (type_identifier) @type)
(array_creation_expression
type: (type_identifier) @type)
(array_type
element: (type_identifier) @type)
(catch_formal_parameter
(type_identifier) @type
name: (identifier) @variable)
(return_statement
(identifier) @variable)
(local_variable_declaration
(variable_declarator
name: (identifier) @variable ))
(for_statement
condition: (binary_expression
(identifier) @variable))
(for_statement
update: (update_expression
(identifier) @variable))
(constructor_declaration
name: (identifier) @class)
(dml_type) @function.defaultLibrary
(bound_apex_expression
(identifier) @variable)
(assignment_operator) @operator
(update_expression ["++" "--"] @operator)
(instanceof_expression
left: (identifier) @variable
right: (type_identifier) @type )
(cast_expression
type: (type_identifier) @type
value: (identifier) @variable)
(switch_expression
condition: (identifier) @variable)
(switch_label
(type_identifier) @type
(identifier) @variable )
(switch_rule
(switch_label
(identifier) @enumMember ))
(trigger_declaration
name: (identifier) @type
object: (identifier) @type
(trigger_event) @keyword
("," (trigger_event) @keyword)*)
(binary_expression
operator: [
">"
"<"
">="
"<="
"=="
"==="
"!="
"!=="
"&&"
"||"
"+"
"-"
"*"
"/"
"&"
"|"
"^"
"%"
"<<"
">>"
">>>"] @operator)
(binary_expression
(identifier) @variable)
(unary_expression
operator: [
"+"
"-"
"!"
"~"
]) @operator
(map_initializer "=>" @operator)
[
(boolean_type)
(void_type)
] @type.defaultLibrary
; Variables
(field_declaration
(modifiers (modifier ["final" "static"])(modifier ["final" "static"]))
(variable_declarator
name: (identifier) @variable.readonly))
(variable_declarator
(identifier) @property)
;; because itendifying it when declared doesn't carry to use
;; leans on the convention that "screaming snake case" is a const
((identifier) @variable.readonly
(#match? @variable.readonly "^_*[A-Z][A-Z\\d_]+$"))
(this) @variable.defaultLibrary
; Literals
[
(int)
] @number
[
(string_literal)
] @string
[
(line_comment)
(block_comment)
] @comment
;; ;; Keywords
[
"abstract"
"break"
"catch"
"class"
"continue"
"default"
"do"
"else"
"enum"
"extends"
"final"
"finally"
"for"
"get"
"global"
"if"
"implements"
"instanceof"
"interface"
"new"
"on"
"private"
"protected"
"public"
"return"
"set"
"static"
"switch"
"testMethod"
"throw"
"transient"
"try"
"trigger"
"virtual"
"when"
"while"
"with_sharing"
"without_sharing"
"inherited_sharing"
] @keyword
(assignment_expression
left: (identifier) @variable)
; (type_identifier) @type ;; not respecting precedence...
;; I don't love this but couldn't break them up right now
;; can't figure out how to let that be special without conflicting
;; in the grammar
"System.runAs" @method.defaultLibrary
(scoped_type_identifier
(type_identifier) @type)

@ -0,0 +1,16 @@
; locals.scm
(method_declaration) @local.scope
(do_statement) @local.scope
(method_declaration
(formal_parameters (formal_parameter (identifier) @local.definition)))
(variable_declarator . (identifier) @local.definition)
(enum_declaration
name: (identifier) @local.definition)
(enum_constant
name: (identifier) @local.definition)
(identifier) @local.reference

@ -0,0 +1,24 @@
(class_declaration
name: (identifier) @name) @definition.class
(interface_declaration
name: (identifier) @name) @definition.interface
(enum_declaration
name: (identifier) @name) @definition.enum
(method_invocation
name: (identifier) @name) @reference.call
(method_declaration
name: (identifier) @name) @definition.method
(interfaces
(type_list
(type_identifier ) @name)) @reference.implementation
(local_variable_declaration
(type_identifier) @name ) @reference.class
(object_creation_expression
type: (type_identifier) @name) @reference.class

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

@ -0,0 +1,224 @@
#ifndef TREE_SITTER_PARSER_H_
#define TREE_SITTER_PARSER_H_
#ifdef __cplusplus
extern "C" {
#endif
#include <stdbool.h>
#include <stdint.h>
#include <stdlib.h>
#define ts_builtin_sym_error ((TSSymbol)-1)
#define ts_builtin_sym_end 0
#define TREE_SITTER_SERIALIZATION_BUFFER_SIZE 1024
typedef uint16_t TSStateId;
#ifndef TREE_SITTER_API_H_
typedef uint16_t TSSymbol;
typedef uint16_t TSFieldId;
typedef struct TSLanguage TSLanguage;
#endif
typedef struct {
TSFieldId field_id;
uint8_t child_index;
bool inherited;
} TSFieldMapEntry;
typedef struct {
uint16_t index;
uint16_t length;
} TSFieldMapSlice;
typedef struct {
bool visible;
bool named;
bool supertype;
} TSSymbolMetadata;
typedef struct TSLexer TSLexer;
struct TSLexer {
int32_t lookahead;
TSSymbol result_symbol;
void (*advance)(TSLexer *, bool);
void (*mark_end)(TSLexer *);
uint32_t (*get_column)(TSLexer *);
bool (*is_at_included_range_start)(const TSLexer *);
bool (*eof)(const TSLexer *);
};
typedef enum {
TSParseActionTypeShift,
TSParseActionTypeReduce,
TSParseActionTypeAccept,
TSParseActionTypeRecover,
} TSParseActionType;
typedef union {
struct {
uint8_t type;
TSStateId state;
bool extra;
bool repetition;
} shift;
struct {
uint8_t type;
uint8_t child_count;
TSSymbol symbol;
int16_t dynamic_precedence;
uint16_t production_id;
} reduce;
uint8_t type;
} TSParseAction;
typedef struct {
uint16_t lex_state;
uint16_t external_lex_state;
} TSLexMode;
typedef union {
TSParseAction action;
struct {
uint8_t count;
bool reusable;
} entry;
} TSParseActionEntry;
struct TSLanguage {
uint32_t version;
uint32_t symbol_count;
uint32_t alias_count;
uint32_t token_count;
uint32_t external_token_count;
uint32_t state_count;
uint32_t large_state_count;
uint32_t production_id_count;
uint32_t field_count;
uint16_t max_alias_sequence_length;
const uint16_t *parse_table;
const uint16_t *small_parse_table;
const uint32_t *small_parse_table_map;
const TSParseActionEntry *parse_actions;
const char * const *symbol_names;
const char * const *field_names;
const TSFieldMapSlice *field_map_slices;
const TSFieldMapEntry *field_map_entries;
const TSSymbolMetadata *symbol_metadata;
const TSSymbol *public_symbol_map;
const uint16_t *alias_map;
const TSSymbol *alias_sequences;
const TSLexMode *lex_modes;
bool (*lex_fn)(TSLexer *, TSStateId);
bool (*keyword_lex_fn)(TSLexer *, TSStateId);
TSSymbol keyword_capture_token;
struct {
const bool *states;
const TSSymbol *symbol_map;
void *(*create)(void);
void (*destroy)(void *);
bool (*scan)(void *, TSLexer *, const bool *symbol_whitelist);
unsigned (*serialize)(void *, char *);
void (*deserialize)(void *, const char *, unsigned);
} external_scanner;
const TSStateId *primary_state_ids;
};
/*
* Lexer Macros
*/
#define START_LEXER() \
bool result = false; \
bool skip = false; \
bool eof = false; \
int32_t lookahead; \
goto start; \
next_state: \
lexer->advance(lexer, skip); \
start: \
skip = false; \
lookahead = lexer->lookahead;
#define ADVANCE(state_value) \
{ \
state = state_value; \
goto next_state; \
}
#define SKIP(state_value) \
{ \
skip = true; \
state = state_value; \
goto next_state; \
}
#define ACCEPT_TOKEN(symbol_value) \
result = true; \
lexer->result_symbol = symbol_value; \
lexer->mark_end(lexer);
#define END_STATE() return result;
/*
* Parse Table Macros
*/
#define SMALL_STATE(id) id - LARGE_STATE_COUNT
#define STATE(id) id
#define ACTIONS(id) id
#define SHIFT(state_value) \
{{ \
.shift = { \
.type = TSParseActionTypeShift, \
.state = state_value \
} \
}}
#define SHIFT_REPEAT(state_value) \
{{ \
.shift = { \
.type = TSParseActionTypeShift, \
.state = state_value, \
.repetition = true \
} \
}}
#define SHIFT_EXTRA() \
{{ \
.shift = { \
.type = TSParseActionTypeShift, \
.extra = true \
} \
}}
#define REDUCE(symbol_val, child_count_val, ...) \
{{ \
.reduce = { \
.type = TSParseActionTypeReduce, \
.symbol = symbol_val, \
.child_count = child_count_val, \
__VA_ARGS__ \
}, \
}}
#define RECOVER() \
{{ \
.type = TSParseActionTypeRecover \
}}
#define ACCEPT_INPUT() \
{{ \
.type = TSParseActionTypeAccept \
}}
#ifdef __cplusplus
}
#endif
#endif // TREE_SITTER_PARSER_H_

@ -0,0 +1,159 @@
================================================================================
ANNOTATIONS name only
================================================================================
@Annotation
public class Me {
}
--------------------------------------------------------------------------------
(parser_output
(class_declaration
(modifiers
(annotation
(identifier))
(modifier))
(identifier)
(class_body)))
================================================================================
ANNOTATIONS name with one bool parameter
================================================================================
@Annotation(param1=false)
public class Me {
}
--------------------------------------------------------------------------------
(parser_output
(class_declaration
(modifiers
(annotation
(identifier)
(annotation_argument_list
(annotation_key_value
(identifier)
(assignment_operator)
(boolean))))
(modifier))
(identifier)
(class_body)))
================================================================================
ANNOTATIONS name with one string parameter
================================================================================
@Annotation(param1='world')
public class Me {
}
--------------------------------------------------------------------------------
(parser_output
(class_declaration
(modifiers
(annotation
(identifier)
(annotation_argument_list
(annotation_key_value
(identifier)
(assignment_operator)
(string_literal))))
(modifier))
(identifier)
(class_body)))
================================================================================
ANNOTATIONS name with multiple parameters
================================================================================
@Annotation(param1=false, param2='hello')
public class Me {
}
--------------------------------------------------------------------------------
(parser_output
(class_declaration
(modifiers
(annotation
(identifier)
(annotation_argument_list
(annotation_key_value
(identifier)
(assignment_operator)
(boolean))
(annotation_key_value
(identifier)
(assignment_operator)
(string_literal))))
(modifier))
(identifier)
(class_body)))
================================================================================
ANNOTATIONS name with string
================================================================================
@Annotation('this is a test of \' strings')
public class Me {
}
--------------------------------------------------------------------------------
(parser_output
(class_declaration
(modifiers
(annotation
(identifier)
(annotation_argument_list
(string_literal)))
(modifier))
(identifier)
(class_body)))
================================================================================
ANNOTATIONS space separated
================================================================================
public without sharing class Me {
{
@InvocableVariable(required=true label='Old User')
public Id oldUserId;
}
}
--------------------------------------------------------------------------------
(parser_output
(class_declaration
(modifiers
(modifier)
(modifier))
(identifier)
(class_body
(block
(local_variable_declaration
(modifiers
(annotation
(identifier)
(annotation_argument_list
(annotation_key_value
(identifier)
(assignment_operator)
(boolean))
(annotation_key_value
(identifier)
(assignment_operator)
(string_literal))))
(modifier))
(type_identifier)
(variable_declarator
(identifier)))))))

@ -0,0 +1,163 @@
================================================================================
ANONYMOUS Simple
================================================================================
String test = 'hello';
System.debug(test);
--------------------------------------------------------------------------------
(parser_output
(local_variable_declaration
(type_identifier)
(variable_declarator
(identifier)
(assignment_operator)
(string_literal)))
(expression_statement
(method_invocation
(identifier)
(identifier)
(argument_list
(identifier)))))
================================================================================
ANONYMOUS with Methods
================================================================================
Integer int1 = 0;
void myProcedure1() {
myProcedure2();
}
void myProcedure2() {
int1++;
}
myProcedure1();
--------------------------------------------------------------------------------
(parser_output
(local_variable_declaration
(type_identifier)
(variable_declarator
(identifier)
(assignment_operator)
(int)))
(method_declaration
(void_type)
(identifier)
(formal_parameters)
(block
(expression_statement
(method_invocation
(identifier)
(argument_list)))))
(method_declaration
(void_type)
(identifier)
(formal_parameters)
(block
(expression_statement
(update_expression
(identifier)))))
(expression_statement
(method_invocation
(identifier)
(argument_list))))
================================================================================
ANONYMOUS with Methods
================================================================================
Integer int1 = 0;
void myProcedure1() {
myProcedure2();
}
void myProcedure2() {
int1++;
}
myProcedure1();
--------------------------------------------------------------------------------
(parser_output
(local_variable_declaration
(type_identifier)
(variable_declarator
(identifier)
(assignment_operator)
(int)))
(method_declaration
(void_type)
(identifier)
(formal_parameters)
(block
(expression_statement
(method_invocation
(identifier)
(argument_list)))))
(method_declaration
(void_type)
(identifier)
(formal_parameters)
(block
(expression_statement
(update_expression
(identifier)))))
(expression_statement
(method_invocation
(identifier)
(argument_list))))
================================================================================
ANONYMOUS with Methods
================================================================================
public class foo {
public void bar() {
system.debug('\n\n#### FOO BAR ####\n\n');
}
}
foo f = new foo();
f.bar();
--------------------------------------------------------------------------------
(parser_output
(class_declaration
(modifiers
(modifier))
(identifier)
(class_body
(method_declaration
(modifiers
(modifier))
(void_type)
(identifier)
(formal_parameters)
(block
(expression_statement
(method_invocation
(identifier)
(identifier)
(argument_list
(string_literal))))))))
(local_variable_declaration
(type_identifier)
(variable_declarator
(identifier)
(assignment_operator)
(object_creation_expression
(type_identifier)
(argument_list))))
(expression_statement
(method_invocation
(identifier)
(identifier)
(argument_list))))

@ -0,0 +1,760 @@
================================================================================
CLASS simple
================================================================================
public class Me {}
--------------------------------------------------------------------------------
(parser_output
(class_declaration
(modifiers
(modifier))
(identifier)
(class_body)))
================================================================================
CLASS private with sharing
================================================================================
private with sharing class Me {}
--------------------------------------------------------------------------------
(parser_output
(class_declaration
(modifiers
(modifier)
(modifier))
(identifier)
(class_body)))
================================================================================
CLASS global without sharing
================================================================================
global without sharing class Me {}
--------------------------------------------------------------------------------
(parser_output
(class_declaration
(modifiers
(modifier)
(modifier))
(identifier)
(class_body)))
================================================================================
CLASS public inherited sharing
================================================================================
public inherited sharing class Me {}
--------------------------------------------------------------------------------
(parser_output
(class_declaration
(modifiers
(modifier)
(modifier))
(identifier)
(class_body)))
================================================================================
CLASS virtual
================================================================================
public inherited sharing virtual class Me {}
--------------------------------------------------------------------------------
(parser_output
(class_declaration
(modifiers
(modifier)
(modifier)
(modifier))
(identifier)
(class_body)))
================================================================================
CLASS abstract
================================================================================
public abstract class Me {}
--------------------------------------------------------------------------------
(parser_output
(class_declaration
(modifiers
(modifier)
(modifier))
(identifier)
(class_body)))
================================================================================
CLASS initializer
================================================================================
public class Me {
{
Integer i = 1;
}
}
--------------------------------------------------------------------------------
(parser_output
(class_declaration
(modifiers
(modifier))
(identifier)
(class_body
(block
(local_variable_declaration
(type_identifier)
(variable_declarator
(identifier)
(assignment_operator)
(int)))))))
================================================================================
CLASS static initializer
================================================================================
public class Me {
{
Integer i = 1;
}
}
--------------------------------------------------------------------------------
(parser_output
(class_declaration
(modifiers
(modifier))
(identifier)
(class_body
(block
(local_variable_declaration
(type_identifier)
(variable_declarator
(identifier)
(assignment_operator)
(int)))))))
================================================================================
CLASS inner class
================================================================================
public class Me {
public class Inside {
{}
}
}
--------------------------------------------------------------------------------
(parser_output
(class_declaration
(modifiers
(modifier))
(identifier)
(class_body
(class_declaration
(modifiers
(modifier))
(identifier)
(class_body
(block))))))
================================================================================
CLASS extending class
================================================================================
public class Me extends OtherClass {
}
--------------------------------------------------------------------------------
(parser_output
(class_declaration
(modifiers
(modifier))
(identifier)
(superclass
(type_identifier))
(class_body)))
================================================================================
CLASS extending class
================================================================================
public class Me implements Interface1 {
}
--------------------------------------------------------------------------------
(parser_output
(class_declaration
(modifiers
(modifier))
(identifier)
(interfaces
(type_list
(type_identifier)))
(class_body)))
================================================================================
CLASS extending class multi
================================================================================
public class Me implements Interface1, Interface2 {
}
--------------------------------------------------------------------------------
(parser_output
(class_declaration
(modifiers
(modifier))
(identifier)
(interfaces
(type_list
(type_identifier)
(type_identifier)))
(class_body)))
================================================================================
CLASS super
================================================================================
public class Subclass extends Superclass {
public override void printName() {
super.printName();
System.debug('But you can call me ' + super.getFirstName());
}
}
--------------------------------------------------------------------------------
(parser_output
(class_declaration
(modifiers
(modifier))
(identifier)
(superclass
(type_identifier))
(class_body
(method_declaration
(modifiers
(modifier)
(modifier))
(void_type)
(identifier)
(formal_parameters)
(block
(expression_statement
(method_invocation
(super)
(identifier)
(argument_list)))
(expression_statement
(method_invocation
(identifier)
(identifier)
(argument_list
(binary_expression
(string_literal)
(method_invocation
(super)
(identifier)
(argument_list)))))))))))
================================================================================
CLASS Extended Class Example
================================================================================
// https://developer.salesforce.com/docs/atlas.en-us.apexcode.meta/apexcode/apex_classes_example.htm
// Top-level (outer) class must be public or global (usually public unless they contain
// a Web Service, then they must be global)
public class OuterClass {
// Static final variable (constant) outer class level only
private static final Integer MY_INT;
// Non-final static variable - use this to communicate state across triggers
// within a single request)
public static String sharedState;
// Static method - outer class level only
public static Integer getInt() { return MY_INT; }
// Static initialization (can be included where the variable is defined)
static {
MY_INT = 2;
}
// Member variable for outer class
private final String m;
// Instance initialization block - can be done where the variable is declared,
// or in a constructor
{
m = 'a';
}
// Because no constructor is explicitly defined in this outer class, an implicit,
// no-argument, public constructor exists
// Inner interface
public virtual interface MyInterface {
// No access modifier is necessary for interface methods - these are always
// public or global depending on the interface visibility
void myMethod();
}
// Interface extension
interface MySecondInterface extends MyInterface {
Integer method2(Integer i);
}
// Inner class - because it is virtual it can be extended.
// This class implements an interface that, in turn, extends another interface.
// Consequently the class must implement all methods.
public virtual class InnerClass implements MySecondInterface {
// Inner member variables
private final String s;
private final String s2;
// Inner instance initialization block (this code could be located above)
{
this.s = 'x';
}
// Inline initialization (happens after the block above executes)
private final Integer i = s.length();
// Explicit no argument constructor
InnerClass() {
// This invokes another constructor that is defined later
this('none');
}
// Constructor that assigns a final variable value
public InnerClass(String s2) {
this.s2 = s2;
}
// Instance method that implements a method from MyInterface.
// Because it is declared virtual it can be overridden by a subclass.
public virtual void myMethod() { /* does nothing */ }
// Implementation of the second interface method above.
// This method references member variables (with and without the "this" prefix)
public Integer method2(Integer i) { return this.i + s.length(); }
}
// Abstract class (that subclasses the class above). No constructor is needed since
// parent class has a no-argument constructor
public abstract class AbstractChildClass extends InnerClass {
// Override the parent class method with this signature.
// Must use the override keyword
public override void myMethod() { /* do something else */ }
// Same name as parent class method, but different signature.
// This is a different method (displaying polymorphism) so it does not need
// to use the override keyword
protected void method2() {}
// Abstract method - subclasses of this class must implement this method
abstract Integer abstractMethod();
}
// Complete the abstract class by implementing its abstract method
public class ConcreteChildClass extends AbstractChildClass {
// Here we expand the visibility of the parent method - note that visibility
// cannot be restricted by a sub-class
public override Integer abstractMethod() { return 5; }
}
// A second sub-class of the original InnerClass
public class AnotherChildClass extends InnerClass {
AnotherChildClass(String s) {
// Explicitly invoke a different super constructor than one with no arguments
super(s);
}
}
// Exception inner class
public virtual class MyException extends Exception {
// Exception class member variable
public Double d;
// Exception class constructor
MyException(Double d) {
this.d = d;
}
// Exception class method, marked as protected
protected void doIt() {}
}
// Exception classes can be abstract and implement interfaces
public abstract class MySecondException extends Exception implements MyInterface {
}
}
--------------------------------------------------------------------------------
(parser_output
(line_comment)
(line_comment)
(line_comment)
(class_declaration
(modifiers
(modifier))
(identifier)
(class_body
(line_comment)
(field_declaration
(modifiers
(modifier)
(modifier)
(modifier))
(type_identifier)
(variable_declarator
(identifier)))
(line_comment)
(line_comment)
(field_declaration
(modifiers
(modifier)
(modifier))
(type_identifier)
(variable_declarator
(identifier)))
(line_comment)
(method_declaration
(modifiers
(modifier)
(modifier))
(type_identifier)
(identifier)
(formal_parameters)
(block
(return_statement
(identifier))))
(line_comment)
(static_initializer
(block
(expression_statement
(assignment_expression
(identifier)
(assignment_operator)
(int)))))
(line_comment)
(field_declaration
(modifiers
(modifier)
(modifier))
(type_identifier)
(variable_declarator
(identifier)))
(line_comment)
(line_comment)
(block
(expression_statement
(assignment_expression
(identifier)
(assignment_operator)
(string_literal))))
(line_comment)
(line_comment)
(line_comment)
(interface_declaration
(modifiers
(modifier)
(modifier))
(identifier)
(interface_body
(line_comment)
(line_comment)
(method_declaration
(void_type)
(identifier)
(formal_parameters))))
(line_comment)
(interface_declaration
(identifier)
(extends_interfaces
(type_list
(type_identifier)))
(interface_body
(method_declaration
(type_identifier)
(identifier)
(formal_parameters
(formal_parameter
(type_identifier)
(identifier))))))
(line_comment)
(line_comment)
(line_comment)
(class_declaration
(modifiers
(modifier)
(modifier))
(identifier)
(interfaces
(type_list
(type_identifier)))
(class_body
(line_comment)
(field_declaration
(modifiers
(modifier)
(modifier))
(type_identifier)
(variable_declarator
(identifier)))
(field_declaration
(modifiers
(modifier)
(modifier))
(type_identifier)
(variable_declarator
(identifier)))
(line_comment)
(block
(expression_statement
(assignment_expression
(field_access
(this)
(identifier))
(assignment_operator)
(string_literal))))
(line_comment)
(field_declaration
(modifiers
(modifier)
(modifier))
(type_identifier)
(variable_declarator
(identifier)
(assignment_operator)
(method_invocation
(identifier)
(identifier)
(argument_list))))
(line_comment)
(constructor_declaration
(identifier)
(formal_parameters)
(constructor_body
(line_comment)
(explicit_constructor_invocation
(this)
(argument_list
(string_literal)))))
(line_comment)
(constructor_declaration
(modifiers
(modifier))
(identifier)
(formal_parameters
(formal_parameter
(type_identifier)
(identifier)))
(constructor_body
(expression_statement
(assignment_expression
(field_access
(this)
(identifier))
(assignment_operator)
(identifier)))))
(line_comment)
(line_comment)
(method_declaration
(modifiers
(modifier)
(modifier))
(void_type)
(identifier)
(formal_parameters)
(block
(block_comment)))
(line_comment)
(line_comment)
(method_declaration
(modifiers
(modifier))
(type_identifier)
(identifier)
(formal_parameters
(formal_parameter
(type_identifier)
(identifier)))
(block
(return_statement
(binary_expression
(field_access
(this)
(identifier))
(method_invocation
(identifier)
(identifier)
(argument_list))))))))
(line_comment)
(line_comment)
(class_declaration
(modifiers
(modifier)
(modifier))
(identifier)
(superclass
(type_identifier))
(class_body
(line_comment)
(line_comment)
(method_declaration
(modifiers
(modifier)
(modifier))
(void_type)
(identifier)
(formal_parameters)
(block
(block_comment)))
(line_comment)
(line_comment)
(line_comment)
(method_declaration
(modifiers
(modifier))
(void_type)
(identifier)
(formal_parameters)
(block))
(line_comment)
(method_declaration
(modifiers
(modifier))
(type_identifier)
(identifier)
(formal_parameters))))
(line_comment)
(class_declaration
(modifiers
(modifier))
(identifier)
(superclass
(type_identifier))
(class_body
(line_comment)
(line_comment)
(method_declaration
(modifiers
(modifier)
(modifier))
(type_identifier)
(identifier)
(formal_parameters)
(block
(return_statement
(int))))))
(line_comment)
(class_declaration
(modifiers
(modifier))
(identifier)
(superclass
(type_identifier))
(class_body
(constructor_declaration
(identifier)
(formal_parameters
(formal_parameter
(type_identifier)
(identifier)))
(constructor_body
(line_comment)
(explicit_constructor_invocation
(super)
(argument_list
(identifier)))))))
(line_comment)
(class_declaration
(modifiers
(modifier)
(modifier))
(identifier)
(superclass
(type_identifier))
(class_body
(line_comment)
(field_declaration
(modifiers
(modifier))
(type_identifier)
(variable_declarator
(identifier)))
(line_comment)
(constructor_declaration
(identifier)
(formal_parameters
(formal_parameter
(type_identifier)
(identifier)))
(constructor_body
(expression_statement
(assignment_expression
(field_access
(this)
(identifier))
(assignment_operator)
(identifier)))))
(line_comment)
(method_declaration
(modifiers
(modifier))
(void_type)
(identifier)
(formal_parameters)
(block))))
(line_comment)
(class_declaration
(modifiers
(modifier)
(modifier))
(identifier)
(superclass
(type_identifier))
(interfaces
(type_list
(type_identifier)))
(class_body)))))
================================================================================
CLASS extending class
================================================================================
/*
"super" https://developer.salesforce.com/docs/atlas.en-us.apexcode.meta/apexcode/apex_classes_keywords_super.htm
Is that different??
"this" keyword https://developer.salesforce.com/docs/atlas.en-us.apexcode.meta/apexcode/apex_classes_keywords_this.htm
*/
--------------------------------------------------------------------------------
(parser_output
(block_comment))

@ -0,0 +1,174 @@
================================================================================
COMMENTS line comment above
================================================================================
// test comment
public class Me {}
--------------------------------------------------------------------------------
(parser_output
(line_comment)
(class_declaration
(modifiers
(modifier))
(identifier)
(class_body)))
================================================================================
COMMENTS line comment after
================================================================================
public class Me {} // test comment
--------------------------------------------------------------------------------
(parser_output
(class_declaration
(modifiers
(modifier))
(identifier)
(class_body))
(line_comment))
================================================================================
COMMENTS line comment below
================================================================================
public class Me {}
// test comment
--------------------------------------------------------------------------------
(parser_output
(class_declaration
(modifiers
(modifier))
(identifier)
(class_body))
(line_comment))
================================================================================
COMMENTS block comment before
================================================================================
/* test comment */
public class Me {}
--------------------------------------------------------------------------------
(parser_output
(block_comment)
(class_declaration
(modifiers
(modifier))
(identifier)
(class_body)))
================================================================================
COMMENTS block comment inside
================================================================================
public class Me {/* test comment */}
--------------------------------------------------------------------------------
(parser_output
(class_declaration
(modifiers
(modifier))
(identifier)
(class_body
(block_comment))))
================================================================================
COMMENTS block comment after
================================================================================
public class Me {}/* test comment */
--------------------------------------------------------------------------------
(parser_output
(class_declaration
(modifiers
(modifier))
(identifier)
(class_body))
(block_comment))
================================================================================
COMMENTS block comment below
================================================================================
public class Me {}
/* test comment */
--------------------------------------------------------------------------------
(parser_output
(class_declaration
(modifiers
(modifier))
(identifier)
(class_body))
(block_comment))
================================================================================
COMMENTS block comment empty
================================================================================
/**/
public class Me {}
--------------------------------------------------------------------------------
(parser_output
(block_comment)
(class_declaration
(modifiers
(modifier))
(identifier)
(class_body)))
================================================================================
COMMENTS block comment multi line
================================================================================
/* line 1
line 2
line 3 */
public class Me {}
--------------------------------------------------------------------------------
(parser_output
(block_comment)
(class_declaration
(modifiers
(modifier))
(identifier)
(class_body)))
================================================================================
COMMENTS block comment more control chars
================================================================================
/***/
/* **/
/** */
/* * /*/
/*/ /* *-/**/
public class Me {}
--------------------------------------------------------------------------------
(parser_output
(block_comment)
(block_comment)
(block_comment)
(block_comment)
(block_comment)
(class_declaration
(modifiers
(modifier))
(identifier)
(class_body)))

@ -0,0 +1,171 @@
================================================================================
CONSTRUCTOR Multiple
================================================================================
public class TestObject2 {
private static final Integer DEFAULT_SIZE = 10;
Integer size;
//Constructor with no arguments
public TestObject2() {
this(DEFAULT_SIZE); // Using this(...) calls the one argument constructor
}
// Constructor with one argument
public TestObject2(Integer ObjectSize) {
size = ObjectSize;
}
}
--------------------------------------------------------------------------------
(parser_output
(class_declaration
(modifiers
(modifier))
(identifier)
(class_body
(field_declaration
(modifiers
(modifier)
(modifier)
(modifier))
(type_identifier)
(variable_declarator
(identifier)
(assignment_operator)
(int)))
(field_declaration
(type_identifier)
(variable_declarator
(identifier)))
(line_comment)
(constructor_declaration
(modifiers
(modifier))
(identifier)
(formal_parameters)
(constructor_body
(explicit_constructor_invocation
(this)
(argument_list
(identifier)))
(line_comment)))
(line_comment)
(constructor_declaration
(modifiers
(modifier))
(identifier)
(formal_parameters
(formal_parameter
(type_identifier)
(identifier)))
(constructor_body
(expression_statement
(assignment_expression
(identifier)
(assignment_operator)
(identifier))))))))
================================================================================
CONSTRUCTOR private
================================================================================
public class TestObject2 {
private static final Integer DEFAULT_SIZE = 10;
Integer size;
private TestObject2() {
this(DEFAULT_SIZE);
}
// Constructor with one argument
private TestObject2(Integer ObjectSize) {
size = ObjectSize;
}
}
--------------------------------------------------------------------------------
(parser_output
(class_declaration
(modifiers
(modifier))
(identifier)
(class_body
(field_declaration
(modifiers
(modifier)
(modifier)
(modifier))
(type_identifier)
(variable_declarator
(identifier)
(assignment_operator)
(int)))
(field_declaration
(type_identifier)
(variable_declarator
(identifier)))
(constructor_declaration
(modifiers
(modifier))
(identifier)
(formal_parameters)
(constructor_body
(explicit_constructor_invocation
(this)
(argument_list
(identifier)))))
(line_comment)
(constructor_declaration
(modifiers
(modifier))
(identifier)
(formal_parameters
(formal_parameter
(type_identifier)
(identifier)))
(constructor_body
(expression_statement
(assignment_expression
(identifier)
(assignment_operator)
(identifier))))))))
================================================================================
CONSTRUCTOR super
================================================================================
public class Subclass extends Superclass {
public Subclass() {
super('Madam', 'Brenda', 'Clapentrap');
}
}
--------------------------------------------------------------------------------
(parser_output
(class_declaration
(modifiers
(modifier))
(identifier)
(superclass
(type_identifier))
(class_body
(constructor_declaration
(modifiers
(modifier))
(identifier)
(formal_parameters)
(constructor_body
(explicit_constructor_invocation
(super)
(argument_list
(string_literal)
(string_literal)
(string_literal))))))))

@ -0,0 +1,429 @@
================================================================================
CONTROL if with braces
================================================================================
public class Me {
{
if(true){
Integer i = 1;
}
}
}
--------------------------------------------------------------------------------
(parser_output
(class_declaration
(modifiers
(modifier))
(identifier)
(class_body
(block
(if_statement
(parenthesized_expression
(boolean))
(block
(local_variable_declaration
(type_identifier)
(variable_declarator
(identifier)
(assignment_operator)
(int)))))))))
================================================================================
CONTROL if without braces
================================================================================
public class Me {
{
if(true)
Integer i = 1;
}
}
--------------------------------------------------------------------------------
(parser_output
(class_declaration
(modifiers
(modifier))
(identifier)
(class_body
(block
(if_statement
(parenthesized_expression
(boolean))
(local_variable_declaration
(type_identifier)
(variable_declarator
(identifier)
(assignment_operator)
(int))))))))
================================================================================
CONTROL if else with braces
================================================================================
public class Me {
{
if(true) {
Integer i = 1;
} else {
Integer j = 2;
}
}
}
--------------------------------------------------------------------------------
(parser_output
(class_declaration
(modifiers
(modifier))
(identifier)
(class_body
(block
(if_statement
(parenthesized_expression
(boolean))
(block
(local_variable_declaration
(type_identifier)
(variable_declarator
(identifier)
(assignment_operator)
(int))))
(block
(local_variable_declaration
(type_identifier)
(variable_declarator
(identifier)
(assignment_operator)
(int)))))))))
================================================================================
CONTROL if else without braces
================================================================================
public class Me {
{
if(true)
Integer i = 1;
else
Integer j = 2;
}
}
--------------------------------------------------------------------------------
(parser_output
(class_declaration
(modifiers
(modifier))
(identifier)
(class_body
(block
(if_statement
(parenthesized_expression
(boolean))
(local_variable_declaration
(type_identifier)
(variable_declarator
(identifier)
(assignment_operator)
(int)))
(local_variable_declaration
(type_identifier)
(variable_declarator
(identifier)
(assignment_operator)
(int))))))))
================================================================================
CONTROL if else without braces
================================================================================
public class Me {
{
if(true)
Integer i = 1;
else if(false)
Integer l = 3;
else
Integer j = 2;
}
}
--------------------------------------------------------------------------------
(parser_output
(class_declaration
(modifiers
(modifier))
(identifier)
(class_body
(block
(if_statement
(parenthesized_expression
(boolean))
(local_variable_declaration
(type_identifier)
(variable_declarator
(identifier)
(assignment_operator)
(int)))
(if_statement
(parenthesized_expression
(boolean))
(local_variable_declaration
(type_identifier)
(variable_declarator
(identifier)
(assignment_operator)
(int)))
(local_variable_declaration
(type_identifier)
(variable_declarator
(identifier)
(assignment_operator)
(int)))))))))
================================================================================
CONTROL else if
================================================================================
public class Me {
{
if(true) {
Integer i = 1;
} else if(false) {
Integer l = 3;
} else {
Integer j = 2;
}
}
}
--------------------------------------------------------------------------------
(parser_output
(class_declaration
(modifiers
(modifier))
(identifier)
(class_body
(block
(if_statement
(parenthesized_expression
(boolean))
(block
(local_variable_declaration
(type_identifier)
(variable_declarator
(identifier)
(assignment_operator)
(int))))
(if_statement
(parenthesized_expression
(boolean))
(block
(local_variable_declaration
(type_identifier)
(variable_declarator
(identifier)
(assignment_operator)
(int))))
(block
(local_variable_declaration
(type_identifier)
(variable_declarator
(identifier)
(assignment_operator)
(int))))))))))
================================================================================
CONTROL do while
================================================================================
public class Me {
{
do {
Integer i = 1;
} while(true);
}
}
--------------------------------------------------------------------------------
(parser_output
(class_declaration
(modifiers
(modifier))
(identifier)
(class_body
(block
(do_statement
(block
(local_variable_declaration
(type_identifier)
(variable_declarator
(identifier)
(assignment_operator)
(int))))
(parenthesized_expression
(boolean)))))))
================================================================================
CONTROL while
================================================================================
public class Me {
{
while (true) {
Integer i = 1;
}
}
}
--------------------------------------------------------------------------------
(parser_output
(class_declaration
(modifiers
(modifier))
(identifier)
(class_body
(block
(while_statement
(parenthesized_expression
(boolean))
(block
(local_variable_declaration
(type_identifier)
(variable_declarator
(identifier)
(assignment_operator)
(int)))))))))
================================================================================
CONTROL for loop with steps
================================================================================
public class Me {
{
for(Integer i = 0; i < 3; i++){
System.debug(i);
}
}
}
--------------------------------------------------------------------------------
(parser_output
(class_declaration
(modifiers
(modifier))
(identifier)
(class_body
(block
(for_statement
(local_variable_declaration
(type_identifier)
(variable_declarator
(identifier)
(assignment_operator)
(int)))
(binary_expression
(identifier)
(int))
(update_expression
(identifier))
(block
(expression_statement
(method_invocation
(identifier)
(identifier)
(argument_list
(identifier))))))))))
================================================================================
CONTROL for loop with iterator
================================================================================
public class Me {
{
List<Account> accs = new List<Account>();
for(Account a : accs){
System.debug(a);
}
}
}
--------------------------------------------------------------------------------
(parser_output
(class_declaration
(modifiers
(modifier))
(identifier)
(class_body
(block
(local_variable_declaration
(generic_type
(type_identifier)
(type_arguments
(type_identifier)))
(variable_declarator
(identifier)
(assignment_operator)
(object_creation_expression
(generic_type
(type_identifier)
(type_arguments
(type_identifier)))
(argument_list))))
(enhanced_for_statement
(type_identifier)
(identifier)
(identifier)
(block
(expression_statement
(method_invocation
(identifier)
(identifier)
(argument_list
(identifier))))))))))
================================================================================
CONTROL runAs
================================================================================
public class Me {
{
System.runAs(new User(Id = UserInfo.getUserId())) {}
}
}
--------------------------------------------------------------------------------
(parser_output
(class_declaration
(modifiers
(modifier))
(identifier)
(class_body
(block
(run_as_statement
(parenthesized_expression
(object_creation_expression
(type_identifier)
(argument_list
(assignment_expression
(identifier)
(assignment_operator)
(method_invocation
(identifier)
(identifier)
(argument_list))))))
(block))))))

@ -0,0 +1,328 @@
================================================================================
DML KEYWORD Insert
================================================================================
public class Me {
{
insert a;
}
}
--------------------------------------------------------------------------------
(parser_output
(class_declaration
(modifiers
(modifier))
(identifier)
(class_body
(block
(expression_statement
(dml_expression
(dml_type)
(identifier)))))))
================================================================================
DML KEYWORD upsert
================================================================================
public class Me {
{
upsert a;
}
}
--------------------------------------------------------------------------------
(parser_output
(class_declaration
(modifiers
(modifier))
(identifier)
(class_body
(block
(expression_statement
(dml_expression
(dml_type)
(identifier)))))))
================================================================================
DML KEYWORD upsert with field
================================================================================
public class Me {
{
upsert a Account.External_Id__c;
}
}
--------------------------------------------------------------------------------
(parser_output
(class_declaration
(modifiers
(modifier))
(identifier)
(class_body
(block
(expression_statement
(dml_expression
(dml_type)
(identifier)
(scoped_type_identifier
(type_identifier)
(type_identifier))))))))
================================================================================
DML KEYWORD update
================================================================================
public class Me {
{
update a;
}
}
--------------------------------------------------------------------------------
(parser_output
(class_declaration
(modifiers
(modifier))
(identifier)
(class_body
(block
(expression_statement
(dml_expression
(dml_type)
(identifier)))))))
================================================================================
DML KEYWORD delete
================================================================================
public class Me {
{
delete a;
}
}
--------------------------------------------------------------------------------
(parser_output
(class_declaration
(modifiers
(modifier))
(identifier)
(class_body
(block
(expression_statement
(dml_expression
(dml_type)
(identifier)))))))
================================================================================
DML KEYWORD undelete
================================================================================
public class Me {
{
undelete a;
}
}
--------------------------------------------------------------------------------
(parser_output
(class_declaration
(modifiers
(modifier))
(identifier)
(class_body
(block
(expression_statement
(dml_expression
(dml_type)
(identifier)))))))
================================================================================
DML KEYWORD merge
================================================================================
public class Me {
{
merge a b;
}
}
--------------------------------------------------------------------------------
(parser_output
(class_declaration
(modifiers
(modifier))
(identifier)
(class_body
(block
(expression_statement
(dml_expression
(dml_type)
(identifier)
(identifier)))))))
================================================================================
DML KEYWORD merge from array
================================================================================
public class Me {
{
merge accounts[0] accounts[1];
}
}
--------------------------------------------------------------------------------
(parser_output
(class_declaration
(modifiers
(modifier))
(identifier)
(class_body
(block
(expression_statement
(dml_expression
(dml_type)
(array_access
(identifier)
(int))
(array_access
(identifier)
(int))))))))
================================================================================
DML KEYWORD merge new list
================================================================================
public class Me {
{
merge masterContact new List<Contact>{oldContact1, oldContact2};
}
}
--------------------------------------------------------------------------------
(parser_output
(class_declaration
(modifiers
(modifier))
(identifier)
(class_body
(block
(expression_statement
(dml_expression
(dml_type)
(identifier)
(array_creation_expression
(generic_type
(type_identifier)
(type_arguments
(type_identifier)))
(array_initializer
(identifier)
(identifier)))))))))
================================================================================
DML KEYWORD upsert from method with field reference
================================================================================
public class Me {
{
upsert contacts.values() Schema.Contact.External_Id__c;
}
}
--------------------------------------------------------------------------------
(parser_output
(class_declaration
(modifiers
(modifier))
(identifier)
(class_body
(block
(expression_statement
(dml_expression
(dml_type)
(method_invocation
(identifier)
(identifier)
(argument_list))
(scoped_type_identifier
(scoped_type_identifier
(type_identifier)
(type_identifier))
(type_identifier))))))))
================================================================================
DML KEYWORD upsert from method with field reference
================================================================================
public class Me {
{
insert new List<Account>{ a1, a2 };
}
}
--------------------------------------------------------------------------------
(parser_output
(class_declaration
(modifiers
(modifier))
(identifier)
(class_body
(block
(expression_statement
(dml_expression
(dml_type)
(array_creation_expression
(generic_type
(type_identifier)
(type_arguments
(type_identifier)))
(array_initializer
(identifier)
(identifier)))))))))
================================================================================
DML KEYWORD insert assigned
================================================================================
public class Me {
{
insert accMG = new Account(Name='matching gift company');
}
}
--------------------------------------------------------------------------------
(parser_output
(class_declaration
(modifiers
(modifier))
(identifier)
(class_body
(block
(expression_statement
(dml_expression
(dml_type)
(assignment_expression
(identifier)
(assignment_operator)
(object_creation_expression
(type_identifier)
(argument_list
(assignment_expression
(identifier)
(assignment_operator)
(string_literal)))))))))))

@ -0,0 +1,48 @@
================================================================================
ENUM declare
================================================================================
public class Me {
public enum Season {WINTER, SPRING, SUMMER, FALL}
}
--------------------------------------------------------------------------------
(parser_output
(class_declaration
(modifiers
(modifier))
(identifier)
(class_body
(enum_declaration
(modifiers
(modifier))
(identifier)
(enum_body
(enum_constant
(identifier))
(enum_constant
(identifier))
(enum_constant
(identifier))
(enum_constant
(identifier)))))))
================================================================================
ENUM class
================================================================================
public enum MyEnumClass { X, Y }
--------------------------------------------------------------------------------
(parser_output
(enum_declaration
(modifiers
(modifier))
(identifier)
(enum_body
(enum_constant
(identifier))
(enum_constant
(identifier)))))

@ -0,0 +1,187 @@
================================================================================
EXCEPTION full
================================================================================
public class Me {
{
Account a = new Account(Name='Acme');
try {
insert a;
} catch(DmlException e) {
// Process exception here
Boolean failed = true;
} catch(Exception e) {
// Process exception here
Boolean failed = true;
} finally {
Boolean finallyRan = true;
}
}
}
--------------------------------------------------------------------------------
(parser_output
(class_declaration
(modifiers
(modifier))
(identifier)
(class_body
(block
(local_variable_declaration
(type_identifier)
(variable_declarator
(identifier)
(assignment_operator)
(object_creation_expression
(type_identifier)
(argument_list
(assignment_expression
(identifier)
(assignment_operator)
(string_literal))))))
(try_statement
(block
(expression_statement
(dml_expression
(dml_type)
(identifier))))
(catch_clause
(catch_formal_parameter
(type_identifier)
(identifier))
(block
(line_comment)
(local_variable_declaration
(type_identifier)
(variable_declarator
(identifier)
(assignment_operator)
(boolean)))))
(catch_clause
(catch_formal_parameter
(type_identifier)
(identifier))
(block
(line_comment)
(local_variable_declaration
(type_identifier)
(variable_declarator
(identifier)
(assignment_operator)
(boolean)))))
(finally_clause
(block
(local_variable_declaration
(type_identifier)
(variable_declarator
(identifier)
(assignment_operator)
(boolean))))))))))
================================================================================
EXCEPTION catch
================================================================================
public class Me {
{
Account a = new Account(Name='Acme');
try {
insert a;
} catch(DmlException e) {
// Process exception here
Boolean failed = true;
}
}
}
--------------------------------------------------------------------------------
(parser_output
(class_declaration
(modifiers
(modifier))
(identifier)
(class_body
(block
(local_variable_declaration
(type_identifier)
(variable_declarator
(identifier)
(assignment_operator)
(object_creation_expression
(type_identifier)
(argument_list
(assignment_expression
(identifier)
(assignment_operator)
(string_literal))))))
(try_statement
(block
(expression_statement
(dml_expression
(dml_type)
(identifier))))
(catch_clause
(catch_formal_parameter
(type_identifier)
(identifier))
(block
(line_comment)
(local_variable_declaration
(type_identifier)
(variable_declarator
(identifier)
(assignment_operator)
(boolean))))))))))
================================================================================
EXCEPTION finally
================================================================================
public class Me {
{
Account a = new Account(Name='Acme');
try {
insert a;
} finally {
Boolean finallyRan = true;
}
}
}
--------------------------------------------------------------------------------
(parser_output
(class_declaration
(modifiers
(modifier))
(identifier)
(class_body
(block
(local_variable_declaration
(type_identifier)
(variable_declarator
(identifier)
(assignment_operator)
(object_creation_expression
(type_identifier)
(argument_list
(assignment_expression
(identifier)
(assignment_operator)
(string_literal))))))
(try_statement
(block
(expression_statement
(dml_expression
(dml_type)
(identifier))))
(finally_clause
(block
(local_variable_declaration
(type_identifier)
(variable_declarator
(identifier)
(assignment_operator)
(boolean))))))))))

@ -0,0 +1,53 @@
================================================================================
EXPRESSIONS Trigger.New
================================================================================
public class Me {
{
TestType evt = Trigger.New;
}
}
--------------------------------------------------------------------------------
(parser_output
(class_declaration
(modifiers
(modifier))
(identifier)
(class_body
(block
(local_variable_declaration
(type_identifier)
(variable_declarator
(identifier)
(assignment_operator)
(field_access
(identifier)
(identifier))))))))
================================================================================
EXPRESSIONS Double Class
================================================================================
public class Me {
{
double.valueOf(1);
}
}
--------------------------------------------------------------------------------
(parser_output
(class_declaration
(modifiers
(modifier))
(identifier)
(class_body
(block
(expression_statement
(method_invocation
(identifier)
(identifier)
(argument_list
(int))))))))

@ -0,0 +1,47 @@
================================================================================
INSTANCEOF
================================================================================
public class Me {
{
SObject a = new Account();
if (a instanceof Account) {
Account = (Account)a;
} else {
// something else...
}
}
}
--------------------------------------------------------------------------------
(parser_output
(class_declaration
(modifiers
(modifier))
(identifier)
(class_body
(block
(local_variable_declaration
(type_identifier)
(variable_declarator
(identifier)
(assignment_operator)
(object_creation_expression
(type_identifier)
(argument_list))))
(if_statement
(parenthesized_expression
(instanceof_expression
(identifier)
(type_identifier)))
(block
(expression_statement
(assignment_expression
(identifier)
(assignment_operator)
(cast_expression
(type_identifier)
(identifier)))))
(block
(line_comment)))))))

@ -0,0 +1,175 @@
================================================================================
METHOD public
================================================================================
public class Me {
public void method1(String param1, Integer param2){
param1 = '1';
param2 = 2;
}
}
--------------------------------------------------------------------------------
(parser_output
(class_declaration
(modifiers
(modifier))
(identifier)
(class_body
(method_declaration
(modifiers
(modifier))
(void_type)
(identifier)
(formal_parameters
(formal_parameter
(type_identifier)
(identifier))
(formal_parameter
(type_identifier)
(identifier)))
(block
(expression_statement
(assignment_expression
(identifier)
(assignment_operator)
(string_literal)))
(expression_statement
(assignment_expression
(identifier)
(assignment_operator)
(int))))))))
================================================================================
METHOD private return
================================================================================
public class Me {
private Integer method1(Integer param1){
return param1;
}
}
--------------------------------------------------------------------------------
(parser_output
(class_declaration
(modifiers
(modifier))
(identifier)
(class_body
(method_declaration
(modifiers
(modifier))
(type_identifier)
(identifier)
(formal_parameters
(formal_parameter
(type_identifier)
(identifier)))
(block
(return_statement
(identifier)))))))
================================================================================
METHOD global static
================================================================================
public class Me {
global static Integer method1(Integer param1){
return param1;
}
}
--------------------------------------------------------------------------------
(parser_output
(class_declaration
(modifiers
(modifier))
(identifier)
(class_body
(method_declaration
(modifiers
(modifier)
(modifier))
(type_identifier)
(identifier)
(formal_parameters
(formal_parameter
(type_identifier)
(identifier)))
(block
(return_statement
(identifier)))))))
================================================================================
METHOD Modifier on parameter
================================================================================
public class Me {
public void helloWorld(final Integer i){
System.debug(i);
}
}
--------------------------------------------------------------------------------
(parser_output
(class_declaration
(modifiers
(modifier))
(identifier)
(class_body
(method_declaration
(modifiers
(modifier))
(void_type)
(identifier)
(formal_parameters
(formal_parameter
(modifiers
(modifier))
(type_identifier)
(identifier)))
(block
(expression_statement
(method_invocation
(identifier)
(identifier)
(argument_list
(identifier)))))))))
================================================================================
METHOD testMethod modifier
================================================================================
public class Me {
public testMethod void helloWorld(){
System.debug(i);
}
}
--------------------------------------------------------------------------------
(parser_output
(class_declaration
(modifiers
(modifier))
(identifier)
(class_body
(method_declaration
(modifiers
(modifier)
(modifier))
(void_type)
(identifier)
(formal_parameters)
(block
(expression_statement
(method_invocation
(identifier)
(identifier)
(argument_list
(identifier)))))))))

File diff suppressed because it is too large Load Diff

@ -0,0 +1,2 @@
TODO...
https://developer.salesforce.com/docs/atlas.en-us.apexcode.meta/apexcode/langCon_apex_expressions_operators_precedence.htm

@ -0,0 +1,302 @@
================================================================================
PROPERTY Class full
================================================================================
public class Me {
public transient final static Integer TEST = 0;
}
--------------------------------------------------------------------------------
(parser_output
(class_declaration
(modifiers
(modifier))
(identifier)
(class_body
(field_declaration
(modifiers
(modifier)
(modifier)
(modifier)
(modifier))
(type_identifier)
(variable_declarator
(identifier)
(assignment_operator)
(int))))))
================================================================================
PROPERTY Class security
================================================================================
public class Me {
public Integer test1;
private Integer test1;
protected Integer test1;
global Integer test1;
Integer test1;
}
--------------------------------------------------------------------------------
(parser_output
(class_declaration
(modifiers
(modifier))
(identifier)
(class_body
(field_declaration
(modifiers
(modifier))
(type_identifier)
(variable_declarator
(identifier)))
(field_declaration
(modifiers
(modifier))
(type_identifier)
(variable_declarator
(identifier)))
(field_declaration
(modifiers
(modifier))
(type_identifier)
(variable_declarator
(identifier)))
(field_declaration
(modifiers
(modifier))
(type_identifier)
(variable_declarator
(identifier)))
(field_declaration
(type_identifier)
(variable_declarator
(identifier))))))
================================================================================
PROPERTY Class modifiers
================================================================================
public class Me {
final Integer test1;
static Integer test1;
transient Integer test1;
static transient Integer test1;
final static Integer test1;
}
--------------------------------------------------------------------------------
(parser_output
(class_declaration
(modifiers
(modifier))
(identifier)
(class_body
(field_declaration
(modifiers
(modifier))
(type_identifier)
(variable_declarator
(identifier)))
(field_declaration
(modifiers
(modifier))
(type_identifier)
(variable_declarator
(identifier)))
(field_declaration
(modifiers
(modifier))
(type_identifier)
(variable_declarator
(identifier)))
(field_declaration
(modifiers
(modifier)
(modifier))
(type_identifier)
(variable_declarator
(identifier)))
(field_declaration
(modifiers
(modifier)
(modifier))
(type_identifier)
(variable_declarator
(identifier))))))
================================================================================
PROPERTY automatic properties
================================================================================
public class Me {
public integer MyReadOnlyProp { get; }
public double MyReadWriteProp { get; set; }
public string MyWriteOnlyProp { set; }
}
--------------------------------------------------------------------------------
(parser_output
(class_declaration
(modifiers
(modifier))
(identifier)
(class_body
(field_declaration
(modifiers
(modifier))
(type_identifier)
(variable_declarator
(identifier))
(accessor_list
(accessor_declaration)))
(field_declaration
(modifiers
(modifier))
(type_identifier)
(variable_declarator
(identifier))
(accessor_list
(accessor_declaration)
(accessor_declaration)))
(field_declaration
(modifiers
(modifier))
(type_identifier)
(variable_declarator
(identifier))
(accessor_list
(accessor_declaration))))))
================================================================================
PROPERTY Access Modifiers
================================================================================
global virtual class Me {
// X is private for read and public for write
public integer X { private get; set; }
// Y can be globally read but only written within a class
global integer Y { get; public set; }
// Z can be read within the class but only subclasses can set it
public integer Z { get; protected set; }
}
--------------------------------------------------------------------------------
(parser_output
(class_declaration
(modifiers
(modifier)
(modifier))
(identifier)
(class_body
(line_comment)
(field_declaration
(modifiers
(modifier))
(type_identifier)
(variable_declarator
(identifier))
(accessor_list
(accessor_declaration
(modifiers
(modifier)))
(accessor_declaration)))
(line_comment)
(field_declaration
(modifiers
(modifier))
(type_identifier)
(variable_declarator
(identifier))
(accessor_list
(accessor_declaration)
(accessor_declaration
(modifiers
(modifier)))))
(line_comment)
(field_declaration
(modifiers
(modifier))
(type_identifier)
(variable_declarator
(identifier))
(accessor_list
(accessor_declaration)
(accessor_declaration
(modifiers
(modifier))))))))
================================================================================
PROPERTY declared
================================================================================
public class Me {
public integer prop {
get { return prop; }
set { prop = value; }
}
}
--------------------------------------------------------------------------------
(parser_output
(class_declaration
(modifiers
(modifier))
(identifier)
(class_body
(field_declaration
(modifiers
(modifier))
(type_identifier)
(variable_declarator
(identifier))
(accessor_list
(accessor_declaration
(block
(return_statement
(identifier))))
(accessor_declaration
(block
(expression_statement
(assignment_expression
(identifier)
(assignment_operator)
(identifier))))))))))
================================================================================
PROPERTY mixed
================================================================================
public class Me {
public integer prop {
get { return prop; }
set;
}
}
--------------------------------------------------------------------------------
(parser_output
(class_declaration
(modifiers
(modifier))
(identifier)
(class_body
(field_declaration
(modifiers
(modifier))
(type_identifier)
(variable_declarator
(identifier))
(accessor_list
(accessor_declaration
(block
(return_statement
(identifier))))
(accessor_declaration))))))

@ -0,0 +1,822 @@
================================================================================
QUERIES SOQL Simple Bound
================================================================================
public class Me {
{
List<Account> accs = [SELECT Id FROM Account
WHERE Name = :var1];
}
}
--------------------------------------------------------------------------------
(parser_output
(class_declaration
(modifiers
(modifier))
(identifier)
(class_body
(block
(local_variable_declaration
(generic_type
(type_identifier)
(type_arguments
(type_identifier)))
(variable_declarator
(identifier)
(assignment_operator)
(query_expression
(soql_query
(soql_query_body
(select_clause
(field_identifier
(identifier)))
(from_clause
(storage_identifier
(identifier)))
(where_clause
(comparison_expression
(field_identifier
(identifier))
(value_comparison_operator)
(bound_apex_expression
(identifier)))))))))))))
================================================================================
QUERIES SOQL Arithmatic in binding
================================================================================
public class Me {
{
List<Account> accs = [SELECT Id FROM Account
WHERE Name = :('x' + 'xx')];
}
}
--------------------------------------------------------------------------------
(parser_output
(class_declaration
(modifiers
(modifier))
(identifier)
(class_body
(block
(local_variable_declaration
(generic_type
(type_identifier)
(type_arguments
(type_identifier)))
(variable_declarator
(identifier)
(assignment_operator)
(query_expression
(soql_query
(soql_query_body
(select_clause
(field_identifier
(identifier)))
(from_clause
(storage_identifier
(identifier)))
(where_clause
(comparison_expression
(field_identifier
(identifier))
(value_comparison_operator)
(bound_apex_expression
(parenthesized_expression
(binary_expression
(string_literal)
(string_literal)))))))))))))))
================================================================================
QUERIES SOQL Nested Query Expression
================================================================================
public class Me {
{
List<Account> accs = [
SELECT Id FROM Account
WHERE Name = :[SELECT Name FROM Account
WHERE Id = :A.Id].Name];
}
}
--------------------------------------------------------------------------------
(parser_output
(class_declaration
(modifiers
(modifier))
(identifier)
(class_body
(block
(local_variable_declaration
(generic_type
(type_identifier)
(type_arguments
(type_identifier)))
(variable_declarator
(identifier)
(assignment_operator)
(query_expression
(soql_query
(soql_query_body
(select_clause
(field_identifier
(identifier)))
(from_clause
(storage_identifier
(identifier)))
(where_clause
(comparison_expression
(field_identifier
(identifier))
(value_comparison_operator)
(bound_apex_expression
(field_access
(query_expression
(soql_query
(soql_query_body
(select_clause
(field_identifier
(identifier)))
(from_clause
(storage_identifier
(identifier)))
(where_clause
(comparison_expression
(field_identifier
(identifier))
(value_comparison_operator)
(bound_apex_expression
(field_access
(identifier)
(identifier))))))))
(identifier))))))))))))))
================================================================================
QUERIES SOQL array access
================================================================================
public class Me {
{
String name = [SELECT Name FROM Account
WHERE Id = :A.Id][0].Name;
}
}
--------------------------------------------------------------------------------
(parser_output
(class_declaration
(modifiers
(modifier))
(identifier)
(class_body
(block
(local_variable_declaration
(type_identifier)
(variable_declarator
(identifier)
(assignment_operator)
(field_access
(array_access
(query_expression
(soql_query
(soql_query_body
(select_clause
(field_identifier
(identifier)))
(from_clause
(storage_identifier
(identifier)))
(where_clause
(comparison_expression
(field_identifier
(identifier))
(value_comparison_operator)
(bound_apex_expression
(field_access
(identifier)
(identifier))))))))
(int))
(identifier))))))))
================================================================================
QUERIES SOQL property access
================================================================================
public class Me {
{
String name = [SELECT Name FROM Account
WHERE Id = :A.Id].Name;
}
}
--------------------------------------------------------------------------------
(parser_output
(class_declaration
(modifiers
(modifier))
(identifier)
(class_body
(block
(local_variable_declaration
(type_identifier)
(variable_declarator
(identifier)
(assignment_operator)
(field_access
(query_expression
(soql_query
(soql_query_body
(select_clause
(field_identifier
(identifier)))
(from_clause
(storage_identifier
(identifier)))
(where_clause
(comparison_expression
(field_identifier
(identifier))
(value_comparison_operator)
(bound_apex_expression
(field_access
(identifier)
(identifier))))))))
(identifier))))))))
================================================================================
QUERIES SOQL Bound Limit
================================================================================
public class Me {
{
Integer i = 1;
List<Account> accs = [SELECT Id FROM Account LIMIT :i];
}
}
--------------------------------------------------------------------------------
(parser_output
(class_declaration
(modifiers
(modifier))
(identifier)
(class_body
(block
(local_variable_declaration
(type_identifier)
(variable_declarator
(identifier)
(assignment_operator)
(int)))
(local_variable_declaration
(generic_type
(type_identifier)
(type_arguments
(type_identifier)))
(variable_declarator
(identifier)
(assignment_operator)
(query_expression
(soql_query
(soql_query_body
(select_clause
(field_identifier
(identifier)))
(from_clause
(storage_identifier
(identifier)))
(limit_clause
(bound_apex_expression
(identifier))))))))))))
================================================================================
QUERIES SOQL Bound Offset
================================================================================
public class Me {
{
Integer i = 1;
List<Account> accs = [SELECT Id FROM Account OFFSET :i];
}
}
--------------------------------------------------------------------------------
(parser_output
(class_declaration
(modifiers
(modifier))
(identifier)
(class_body
(block
(local_variable_declaration
(type_identifier)
(variable_declarator
(identifier)
(assignment_operator)
(int)))
(local_variable_declaration
(generic_type
(type_identifier)
(type_arguments
(type_identifier)))
(variable_declarator
(identifier)
(assignment_operator)
(query_expression
(soql_query
(soql_query_body
(select_clause
(field_identifier
(identifier)))
(from_clause
(storage_identifier
(identifier)))
(offset_clause
(bound_apex_expression
(identifier))))))))))))
================================================================================
QUERIES SOQL ALL ROWS
================================================================================
public class Me {
{
Integer i = 1;
Integer cnt = [SELECT COUNT() FROM Contact ALL ROWS];
}
}
--------------------------------------------------------------------------------
(parser_output
(class_declaration
(modifiers
(modifier))
(identifier)
(class_body
(block
(local_variable_declaration
(type_identifier)
(variable_declarator
(identifier)
(assignment_operator)
(int)))
(local_variable_declaration
(type_identifier)
(variable_declarator
(identifier)
(assignment_operator)
(query_expression
(soql_query
(soql_query_body
(select_clause
(count_expression
(function_name)))
(from_clause
(storage_identifier
(identifier)))
(all_rows_clause))))))))))
================================================================================
QUERIES SOQL Complex bound expression without parens
================================================================================
public class Me {
{
String a = 'A';
List<Account> accs = [SELECT Id FROM Account WHERE Name = :'N'+a+'M'+'E' AND Name = 'NOPE'];
}
}
--------------------------------------------------------------------------------
(parser_output
(class_declaration
(modifiers
(modifier))
(identifier)
(class_body
(block
(local_variable_declaration
(type_identifier)
(variable_declarator
(identifier)
(assignment_operator)
(string_literal)))
(local_variable_declaration
(generic_type
(type_identifier)
(type_arguments
(type_identifier)))
(variable_declarator
(identifier)
(assignment_operator)
(query_expression
(soql_query
(soql_query_body
(select_clause
(field_identifier
(identifier)))
(from_clause
(storage_identifier
(identifier)))
(where_clause
(and_expression
(comparison_expression
(field_identifier
(identifier))
(value_comparison_operator)
(bound_apex_expression
(binary_expression
(binary_expression
(binary_expression
(string_literal)
(identifier))
(string_literal))
(string_literal))))
(comparison_expression
(field_identifier
(identifier))
(value_comparison_operator)
(string_literal)))))))))))))
================================================================================
QUERIES SOQL
================================================================================
public class Me {
{
List<Account> accs = [SELECT Id, Name FROM Account];
}
}
--------------------------------------------------------------------------------
(parser_output
(class_declaration
(modifiers
(modifier))
(identifier)
(class_body
(block
(local_variable_declaration
(generic_type
(type_identifier)
(type_arguments
(type_identifier)))
(variable_declarator
(identifier)
(assignment_operator)
(query_expression
(soql_query
(soql_query_body
(select_clause
(field_identifier
(identifier))
(field_identifier
(identifier)))
(from_clause
(storage_identifier
(identifier))))))))))))
================================================================================
QUERIES SOQL iterator
================================================================================
public class Me {
{
for(Account a : [SELECT Id FROM Account]){
System.debug(a);
}
}
}
--------------------------------------------------------------------------------
(parser_output
(class_declaration
(modifiers
(modifier))
(identifier)
(class_body
(block
(enhanced_for_statement
(type_identifier)
(identifier)
(query_expression
(soql_query
(soql_query_body
(select_clause
(field_identifier
(identifier)))
(from_clause
(storage_identifier
(identifier))))))
(block
(expression_statement
(method_invocation
(identifier)
(identifier)
(argument_list
(identifier))))))))))
================================================================================
QUERIES SOQL For Collection
================================================================================
public class Me {
{
for(List<Account> accs : [SELECT Id FROM Account]){
for(Account a : accs){
System.debug(a);
}
}
}
}
--------------------------------------------------------------------------------
(parser_output
(class_declaration
(modifiers
(modifier))
(identifier)
(class_body
(block
(enhanced_for_statement
(generic_type
(type_identifier)
(type_arguments
(type_identifier)))
(identifier)
(query_expression
(soql_query
(soql_query_body
(select_clause
(field_identifier
(identifier)))
(from_clause
(storage_identifier
(identifier))))))
(block
(enhanced_for_statement
(type_identifier)
(identifier)
(identifier)
(block
(expression_statement
(method_invocation
(identifier)
(identifier)
(argument_list
(identifier))))))))))))
================================================================================
QUERIES SOSL Term
================================================================================
public class Me {
{
List<List<SObject>> res =
[FIND 'hello' RETURNING Account];
}
}
--------------------------------------------------------------------------------
(parser_output
(class_declaration
(modifiers
(modifier))
(identifier)
(class_body
(block
(local_variable_declaration
(generic_type
(type_identifier)
(type_arguments
(generic_type
(type_identifier)
(type_arguments
(type_identifier)))))
(variable_declarator
(identifier)
(assignment_operator)
(query_expression
(sosl_query
(sosl_query_body
(find_clause
(term_separator_start)
(term)
(term_separator_end))
(returning_clause
(sobject_return
(identifier))))))))))))
================================================================================
QUERIES SOSL Bindings
================================================================================
public class Me {
{
List<List<SObject>> res =
[FIND :myString1 IN ALL FIELDS
RETURNING
Account (Id, Name WHERE Name LIKE :myString2
LIMIT :myInt3),
Contact,
Opportunity,
Lead
WITH DIVISION =:myString4
LIMIT :myInt5];
}
}
--------------------------------------------------------------------------------
(parser_output
(class_declaration
(modifiers
(modifier))
(identifier)
(class_body
(block
(local_variable_declaration
(generic_type
(type_identifier)
(type_arguments
(generic_type
(type_identifier)
(type_arguments
(type_identifier)))))
(variable_declarator
(identifier)
(assignment_operator)
(query_expression
(sosl_query
(sosl_query_body
(find_clause
(bound_apex_expression
(identifier)))
(in_clause
(in_type))
(returning_clause
(sobject_return
(identifier)
(selected_fields
(field_identifier
(identifier))
(field_identifier
(identifier)))
(where_clause
(comparison_expression
(field_identifier
(identifier))
(value_comparison_operator)
(bound_apex_expression
(identifier))))
(limit_clause
(bound_apex_expression
(identifier))))
(sobject_return
(identifier))
(sobject_return
(identifier))
(sobject_return
(identifier)))
(with_clause
(with_type
(with_division_expression
(bound_apex_expression
(identifier)))))
(limit_clause
(bound_apex_expression
(identifier))))))))))))
================================================================================
QUERIES SOQL Includes with Parens
================================================================================
public class Me {
{
[
SELECT Body__c
FROM Banner__c
WHERE
Language__c = :langCode
AND Visible__c = TRUE
AND Channel__c INCLUDES (:channel)
AND Market__c INCLUDES (:marketCode)
ORDER BY Order__c
];
}
}
--------------------------------------------------------------------------------
(parser_output
(class_declaration
(modifiers
(modifier))
(identifier)
(class_body
(block
(expression_statement
(query_expression
(soql_query
(soql_query_body
(select_clause
(field_identifier
(identifier)))
(from_clause
(storage_identifier
(identifier)))
(where_clause
(and_expression
(comparison_expression
(field_identifier
(identifier))
(value_comparison_operator)
(bound_apex_expression
(identifier)))
(comparison_expression
(field_identifier
(identifier))
(value_comparison_operator)
(boolean))
(comparison_expression
(field_identifier
(identifier))
(set_comparison_operator)
(bound_apex_expression
(identifier)))
(comparison_expression
(field_identifier
(identifier))
(set_comparison_operator)
(bound_apex_expression
(identifier)))))
(order_by_clause
(order_expression
(field_identifier
(identifier))))))))))))
================================================================================
QUERIES SOQL Date Literal With Param
================================================================================
public class Me {
{
List<Account> accounts = [
SELECT Id
FROM Account
WHERE CreatedDate = LAST_N_DAYS:60
];
}
}
--------------------------------------------------------------------------------
(parser_output
(class_declaration
(modifiers
(modifier))
(identifier)
(class_body
(block
(local_variable_declaration
(generic_type
(type_identifier)
(type_arguments
(type_identifier)))
(variable_declarator
(identifier)
(assignment_operator)
(query_expression
(soql_query
(soql_query_body
(select_clause
(field_identifier
(identifier)))
(from_clause
(storage_identifier
(identifier)))
(where_clause
(comparison_expression
(field_identifier
(identifier))
(value_comparison_operator)
(date_literal_with_param
(date_literal)
(int)))))))))))))

@ -0,0 +1,489 @@
================================================================================
SWITCH
================================================================================
public class Me {
{
Integer i = 0;
switch on i {
when 2 {
System.debug('when block 2');
}
when null {
System.debug('bad integer');
}
when else {
System.debug('default ' + i);
}
}
}
}
--------------------------------------------------------------------------------
(parser_output
(class_declaration
(modifiers
(modifier))
(identifier)
(class_body
(block
(local_variable_declaration
(type_identifier)
(variable_declarator
(identifier)
(assignment_operator)
(int)))
(switch_expression
(identifier)
(switch_block
(switch_rule
(switch_label
(int))
(block
(expression_statement
(method_invocation
(identifier)
(identifier)
(argument_list
(string_literal))))))
(switch_rule
(switch_label
(null_literal))
(block
(expression_statement
(method_invocation
(identifier)
(identifier)
(argument_list
(string_literal))))))
(switch_rule
(switch_label)
(block
(expression_statement
(method_invocation
(identifier)
(identifier)
(argument_list
(binary_expression
(string_literal)
(identifier)))))))))))))
================================================================================
SWITCH multiple
================================================================================
public class Me {
{
Integer i = 0;
switch on i {
when 2, 3, 4 {
System.debug('when block 2 and 3 and 4');
}
when 5, 6 {
System.debug('when block 5 and 6');
}
when 7 {
System.debug('when block 7');
}
when else {
System.debug('default');
}
}
}
}
--------------------------------------------------------------------------------
(parser_output
(class_declaration
(modifiers
(modifier))
(identifier)
(class_body
(block
(local_variable_declaration
(type_identifier)
(variable_declarator
(identifier)
(assignment_operator)
(int)))
(switch_expression
(identifier)
(switch_block
(switch_rule
(switch_label
(int)
(int)
(int))
(block
(expression_statement
(method_invocation
(identifier)
(identifier)
(argument_list
(string_literal))))))
(switch_rule
(switch_label
(int)
(int))
(block
(expression_statement
(method_invocation
(identifier)
(identifier)
(argument_list
(string_literal))))))
(switch_rule
(switch_label
(int))
(block
(expression_statement
(method_invocation
(identifier)
(identifier)
(argument_list
(string_literal))))))
(switch_rule
(switch_label)
(block
(expression_statement
(method_invocation
(identifier)
(identifier)
(argument_list
(string_literal))))))))))))
================================================================================
SWITCH method results
================================================================================
public class Me {
{
Integer i = 0;
switch on someInteger(i) {
when 2 {
System.debug('when block 2');
}
when 3 {
System.debug('when block 3');
}
when else {
System.debug('default');
}
}
}
}
--------------------------------------------------------------------------------
(parser_output
(class_declaration
(modifiers
(modifier))
(identifier)
(class_body
(block
(local_variable_declaration
(type_identifier)
(variable_declarator
(identifier)
(assignment_operator)
(int)))
(switch_expression
(method_invocation
(identifier)
(argument_list
(identifier)))
(switch_block
(switch_rule
(switch_label
(int))
(block
(expression_statement
(method_invocation
(identifier)
(identifier)
(argument_list
(string_literal))))))
(switch_rule
(switch_label
(int))
(block
(expression_statement
(method_invocation
(identifier)
(identifier)
(argument_list
(string_literal))))))
(switch_rule
(switch_label)
(block
(expression_statement
(method_invocation
(identifier)
(identifier)
(argument_list
(string_literal))))))))))))
================================================================================
SWITCH sObject
================================================================================
public class Me {
{
SObject s = new Account();
switch on s {
when Account a {
System.debug('account ' + a);
}
when Contact c {
System.debug('contact ' + c);
}
when null {
System.debug('null');
}
when else {
System.debug('default');
}
}
}
}
--------------------------------------------------------------------------------
(parser_output
(class_declaration
(modifiers
(modifier))
(identifier)
(class_body
(block
(local_variable_declaration
(type_identifier)
(variable_declarator
(identifier)
(assignment_operator)
(object_creation_expression
(type_identifier)
(argument_list))))
(switch_expression
(identifier)
(switch_block
(switch_rule
(switch_label
(type_identifier)
(identifier))
(block
(expression_statement
(method_invocation
(identifier)
(identifier)
(argument_list
(binary_expression
(string_literal)
(identifier)))))))
(switch_rule
(switch_label
(type_identifier)
(identifier))
(block
(expression_statement
(method_invocation
(identifier)
(identifier)
(argument_list
(binary_expression
(string_literal)
(identifier)))))))
(switch_rule
(switch_label
(null_literal))
(block
(expression_statement
(method_invocation
(identifier)
(identifier)
(argument_list
(string_literal))))))
(switch_rule
(switch_label)
(block
(expression_statement
(method_invocation
(identifier)
(identifier)
(argument_list
(string_literal))))))))))))
================================================================================
SWITCH Enum
================================================================================
public class Me {
{
SObject s = new Account();
switch on season {
when WINTER {
System.debug('boots');
}
when SPRING, SUMMER {
System.debug('sandals');
}
when else {
System.debug('none of the above');
}
}
}
}
--------------------------------------------------------------------------------
(parser_output
(class_declaration
(modifiers
(modifier))
(identifier)
(class_body
(block
(local_variable_declaration
(type_identifier)
(variable_declarator
(identifier)
(assignment_operator)
(object_creation_expression
(type_identifier)
(argument_list))))
(switch_expression
(identifier)
(switch_block
(switch_rule
(switch_label
(identifier))
(block
(expression_statement
(method_invocation
(identifier)
(identifier)
(argument_list
(string_literal))))))
(switch_rule
(switch_label
(identifier)
(identifier))
(block
(expression_statement
(method_invocation
(identifier)
(identifier)
(argument_list
(string_literal))))))
(switch_rule
(switch_label)
(block
(expression_statement
(method_invocation
(identifier)
(identifier)
(argument_list
(string_literal))))))))))))
================================================================================
SWITCH With Parens
================================================================================
public class Me {
{
switch on (x) {
when 1 { return 1; }
when ((2)) { return 2; }
when (3), (4) { return 3; }
}
}
}
--------------------------------------------------------------------------------
(parser_output
(class_declaration
(modifiers
(modifier))
(identifier)
(class_body
(block
(switch_expression
(parenthesized_expression
(identifier))
(switch_block
(switch_rule
(switch_label
(int))
(block
(return_statement
(int))))
(switch_rule
(switch_label
(parenthesized_expression
(parenthesized_expression
(int))))
(block
(return_statement
(int))))
(switch_rule
(switch_label
(parenthesized_expression
(int))
(parenthesized_expression
(int)))
(block
(return_statement
(int))))))))))
================================================================================
SWITCH on values
================================================================================
public class Me {
{
switch on monthsSinceFiscalStart {
when 1, 2, 3, -9, -10, -11 {
fiscalQuarter = 1;
}
}
}
}
--------------------------------------------------------------------------------
(parser_output
(class_declaration
(modifiers
(modifier))
(identifier)
(class_body
(block
(switch_expression
(identifier)
(switch_block
(switch_rule
(switch_label
(int)
(int)
(int)
(unary_expression
(int))
(unary_expression
(int))
(unary_expression
(int)))
(block
(expression_statement
(assignment_expression
(identifier)
(assignment_operator)
(int)))))))))))

@ -0,0 +1,36 @@
================================================================================
TRIGGER with all events
================================================================================
trigger myAccountTrigger on Account (
before insert,
before update,
before delete,
after insert,
after update,
after delete,
after undelete) {
Integer i = 1;
}
--------------------------------------------------------------------------------
(parser_output
(trigger_declaration
(identifier)
(identifier)
(trigger_event)
(trigger_event)
(trigger_event)
(trigger_event)
(trigger_event)
(trigger_event)
(trigger_event)
(trigger_body
(block
(local_variable_declaration
(type_identifier)
(variable_declarator
(identifier)
(assignment_operator)
(int)))))))

@ -0,0 +1,428 @@
================================================================================
VARIABLE list initialized with new list
================================================================================
public class Me {
{
List<Integer> ints = new List<Integer>();
}
}
--------------------------------------------------------------------------------
(parser_output
(class_declaration
(modifiers
(modifier))
(identifier)
(class_body
(block
(local_variable_declaration
(generic_type
(type_identifier)
(type_arguments
(type_identifier)))
(variable_declarator
(identifier)
(assignment_operator)
(object_creation_expression
(generic_type
(type_identifier)
(type_arguments
(type_identifier)))
(argument_list))))))))
================================================================================
VARIABLE list initialized with populated list
================================================================================
public class Me {
{
List<Integer> ints = new List<Integer>{1,2,3};
}
}
--------------------------------------------------------------------------------
(parser_output
(class_declaration
(modifiers
(modifier))
(identifier)
(class_body
(block
(local_variable_declaration
(generic_type
(type_identifier)
(type_arguments
(type_identifier)))
(variable_declarator
(identifier)
(assignment_operator)
(array_creation_expression
(generic_type
(type_identifier)
(type_arguments
(type_identifier)))
(array_initializer
(int)
(int)
(int)))))))))
================================================================================
VARIABLE list initialized with new array
================================================================================
public class Me {
{
List<Integer> ints = new Integer[0];
}
}
--------------------------------------------------------------------------------
(parser_output
(class_declaration
(modifiers
(modifier))
(identifier)
(class_body
(block
(local_variable_declaration
(generic_type
(type_identifier)
(type_arguments
(type_identifier)))
(variable_declarator
(identifier)
(assignment_operator)
(array_creation_expression
(type_identifier)
(dimensions_expr
(int)))))))))
================================================================================
VARIABLE list initialized with populated array
================================================================================
public class Me {
{
List<Integer> ints = new Integer[]{1,2,3};
}
}
--------------------------------------------------------------------------------
(parser_output
(class_declaration
(modifiers
(modifier))
(identifier)
(class_body
(block
(local_variable_declaration
(generic_type
(type_identifier)
(type_arguments
(type_identifier)))
(variable_declarator
(identifier)
(assignment_operator)
(array_creation_expression
(type_identifier)
(dimensions)
(array_initializer
(int)
(int)
(int)))))))))
================================================================================
VARIABLE array filled with new array
================================================================================
public class Me {
{
Integer[] ints = new Integer[0];
}
}
--------------------------------------------------------------------------------
(parser_output
(class_declaration
(modifiers
(modifier))
(identifier)
(class_body
(block
(local_variable_declaration
(array_type
(type_identifier)
(dimensions))
(variable_declarator
(identifier)
(assignment_operator)
(array_creation_expression
(type_identifier)
(dimensions_expr
(int)))))))))
================================================================================
VARIABLE Set with new
================================================================================
public class Me {
{
Set<Integer> ints = new Set<Integer>();
}
}
--------------------------------------------------------------------------------
(parser_output
(class_declaration
(modifiers
(modifier))
(identifier)
(class_body
(block
(local_variable_declaration
(generic_type
(type_identifier)
(type_arguments
(type_identifier)))
(variable_declarator
(identifier)
(assignment_operator)
(object_creation_expression
(generic_type
(type_identifier)
(type_arguments
(type_identifier)))
(argument_list))))))))
================================================================================
VARIABLE Set with populated
================================================================================
public class Me {
{
Set<Integer> ints = new Set<Integer>{1,2,3};
}
}
--------------------------------------------------------------------------------
(parser_output
(class_declaration
(modifiers
(modifier))
(identifier)
(class_body
(block
(local_variable_declaration
(generic_type
(type_identifier)
(type_arguments
(type_identifier)))
(variable_declarator
(identifier)
(assignment_operator)
(array_creation_expression
(generic_type
(type_identifier)
(type_arguments
(type_identifier)))
(array_initializer
(int)
(int)
(int)))))))))
================================================================================
VARIABLE Map with new
================================================================================
public class Me {
{
Map<String,Integer> intsBymap = new Map<String,Integer>();
}
}
--------------------------------------------------------------------------------
(parser_output
(class_declaration
(modifiers
(modifier))
(identifier)
(class_body
(block
(local_variable_declaration
(generic_type
(type_identifier)
(type_arguments
(type_identifier)
(type_identifier)))
(variable_declarator
(identifier)
(assignment_operator)
(object_creation_expression
(generic_type
(type_identifier)
(type_arguments
(type_identifier)
(type_identifier)))
(argument_list))))))))
================================================================================
VARIABLE Map with populated
================================================================================
public class Me {
{
Map<String,Integer> intsBymap = new Map<String,Integer>{'hello' => 1, 'world' => 2};
}
}
--------------------------------------------------------------------------------
(parser_output
(class_declaration
(modifiers
(modifier))
(identifier)
(class_body
(block
(local_variable_declaration
(generic_type
(type_identifier)
(type_arguments
(type_identifier)
(type_identifier)))
(variable_declarator
(identifier)
(assignment_operator)
(map_creation_expression
(generic_type
(type_identifier)
(type_arguments
(type_identifier)
(type_identifier)))
(map_initializer
(string_literal)
(int)
(string_literal)
(int)))))))))
================================================================================
VARIABLE initialize multiple on a line
================================================================================
public class Me {
{
Integer i,j,k;
}
}
--------------------------------------------------------------------------------
(parser_output
(class_declaration
(modifiers
(modifier))
(identifier)
(class_body
(block
(local_variable_declaration
(type_identifier)
(variable_declarator
(identifier))
(variable_declarator
(identifier))
(variable_declarator
(identifier)))))))
================================================================================
VARIABLE initialize multiple on a line sparse values
================================================================================
public class Me {
{
Integer i = 0, j, k = 1;
}
}
--------------------------------------------------------------------------------
(parser_output
(class_declaration
(modifiers
(modifier))
(identifier)
(class_body
(block
(local_variable_declaration
(type_identifier)
(variable_declarator
(identifier)
(assignment_operator)
(int))
(variable_declarator
(identifier))
(variable_declarator
(identifier)
(assignment_operator)
(int)))))))
================================================================================
VARIABLE unicode in string
================================================================================
public class Me {
{
String v = 'Hello\u2019 from world\U2019';
}
}
--------------------------------------------------------------------------------
(parser_output
(class_declaration
(modifiers
(modifier))
(identifier)
(class_body
(block
(local_variable_declaration
(type_identifier)
(variable_declarator
(identifier)
(assignment_operator)
(string_literal)))))))
================================================================================
VARIABLE negative int
================================================================================
public class Me {
{
Integer i = -1;
}
}
--------------------------------------------------------------------------------
(parser_output
(class_declaration
(modifiers
(modifier))
(identifier)
(class_body
(block
(local_variable_declaration
(type_identifier)
(variable_declarator
(identifier)
(assignment_operator)
(unary_expression
(int))))))))

@ -0,0 +1,55 @@
@Annotation(param1=false, param2='hello')
// <- operator
// ^ decorator
// ^ punctuation
// ^ variable
// ^ operator
// ^ variable.readonly.defaultLibrary
// ^ punctuation
// ^ variable
// ^ operator
// ^ string
// ^ punctuation
public class Me {{
// <- keyword
// ^ keyword
// ^ class
// ^ punctuation
// ^ punctuation
@InvocableVariable(required=true label='Old User')
// ^ operator
// ^ decorator
// ^ punctuation
// ^ variable
// ^ operator
// ^ variable.readonly.defaultLibrary
// ^ variable
// ^ operator
// ^ string
// ^ punctuation
public Id oldUserId;// TODO: this isn't a local variable declaration, it should be a field declaration
// ^ keyword
// ^ type
// ^ variable
}
//^ punctuation
@Annotation('this is a test of \' strings')
//^ operator
// ^ decorator
// ^ punctuation
// ^ string
// ^ punctuation
public class Me {
// ^ keyword
// ^ keyword
// ^ class
// ^ punctuation
}
//^ punctuation
}
// <- punctuation

@ -0,0 +1,53 @@
public class Me extends You {
// <- keyword
// ^ keyword
// ^ class
// ^ keyword
// ^ class
// ^ punctuation
private String world;
//^ keyword
// ^ type
// ^ property
public Me() {
//^ keyword
// ^ class
// ^ punctuation
// ^ punctuation
this('foo');
// ^ variable.defaultLibrary
// ^ punctuation
// ^ string
// ^ punctuation
// ^ punctuation
}
//^ punctuation
private Me(String hello){
//^ keyword
// ^ class
// ^ punctuation
// ^ type
// ^ variable
// ^ punctuation
// ^ punctuation
super(hello);
// ^ function.defaultLibrary
// ^ punctuation
// ^ variable
// ^ punctuation
// ^ punctuation
this.world = hello;
// ^ variable.defaultLibrary
// ^ punctuation
// ^ property
// ^ operator
// ^ variable
}
//^ punctuation
}
// <- punctuation

@ -0,0 +1,242 @@
public class Me {
// <- keyword
// ^ keyword
// ^ class
// ^ punctuation
{
// ^ punctuation
if(true){
// ^ keyword
// ^ punctuation
// ^ variable.readonly.defaultLibrary
// ^ punctuation
// ^ punctuation
Integer i = 1;
// ^ type
// ^ variable
// ^ operator
// ^ number
// ^ punctuation
}
// ^ punctuation
if(true)
// ^ keyword
// ^ punctuation
// ^ variable.readonly.defaultLibrary
// ^ punctuation
Integer i = 1;
// ^ type
// ^ variable
// ^ operator
// ^ number
// ^ punctuation
if(true) {
// ^ keyword
// ^ punctuation
// ^ variable.readonly.defaultLibrary
// ^ punctuation
// ^ punctuation
Integer i = 1;
// ^ type
// ^ variable
// ^ operator
// ^ number
// ^ punctuation
} else {
// ^ punctuation
// ^ keyword
// ^ punctuation
Integer j = 2;
// ^ type
// ^ variable
// ^ operator
// ^ number
// ^ punctuation
}
// ^ punctuation
if(true)
// ^ keyword
// ^ punctuation
// ^ variable.readonly.defaultLibrary
// ^ punctuation
Integer i = 1;
// ^ type
// ^ variable
// ^ operator
// ^ number
// ^ punctuation
else
// ^ keyword
Integer j = 2;
// ^ type
// ^ variable
// ^ operator
// ^ number
// ^ punctuation
if(true)
// ^ keyword
// ^ punctuation
// ^ variable.readonly.defaultLibrary
// ^ punctuation
Integer i = 1;
// ^ type
// ^ variable
// ^ operator
// ^ number
// ^ punctuation
else if(false)
// ^ keyword
// ^ keyword
// ^ punctuation
// ^ variable.readonly.defaultLibrary
// ^ punctuation
Integer l = 3;
// ^ type
// ^ variable
// ^ operator
// ^ number
// ^ punctuation
else
// ^ keyword
Integer j = 2;
// ^ type
// ^ variable
// ^ operator
// ^ number
// ^ punctuation
if(true) {
// ^ keyword
// ^ punctuation
// ^ variable.readonly.defaultLibrary
// ^ punctuation
// ^ punctuation
Integer i = 1;
// ^ type
// ^ variable
// ^ operator
// ^ number
// ^ punctuation
} else if(false) {
// ^ punctuation
// ^ keyword
// ^ keyword
// ^ punctuation
// ^ variable.readonly.defaultLibrary
// ^ punctuation
// ^ punctuation
Integer l = 3;
// ^ type
// ^ variable
// ^ operator
// ^ number
// ^ punctuation
} else {
// ^ punctuation
// ^ keyword
// ^ punctuation
Integer j = 2;
// ^ type
// ^ variable
// ^ operator
// ^ number
// ^ punctuation
}
// ^ punctuation
do {
// ^ keyword
// ^ punctuation
Integer i = 1;
// ^ type
// ^ variable
// ^ operator
// ^ number
// ^ punctuation
} while(true);
// ^ punctuation
// ^ keyword
// ^ punctuation
// ^ variable.readonly.defaultLibrary
// ^ punctuation
// ^ punctuation
while (true) {
// ^ keyword
// ^ punctuation
// ^ variable.readonly.defaultLibrary
// ^ punctuation
// ^ punctuation
Integer i = 1;
// ^ type
// ^ variable
// ^ operator
// ^ number
// ^ punctuation
}
// ^ punctuation
for(Integer i = 0; i < 3; i++){
// ^ keyword
// ^ punctuation
// ^ type
// ^ variable
// ^ operator
// ^ number
// ^ punctuation
// ^ variable
// ^ operator
// ^ number
// ^ punctuation
// ^ variable
// ^^ operator
// ^ punctuation
// ^ punctuation
System.debug(i);
// ^ type
// ^ punctuation
// ^ method
// ^ punctuation
// ^ variable
// ^ punctuation
}
// ^ punctuation
for(Account a : accs){
// ^ keyword
// ^ punctuation
// ^ type
// ^ variable
// ^ punctuation
// ^ variable
// ^ punctuation
// ^ punctuation
System.debug(a);
// ^ type
// ^ punctuation
// ^ method
// ^ punctuation
// ^ variable
// ^ punctuation
}
// ^ punctuation
System.runAs(new User(Id = UserInfo.getUserId())) {}
// ^^^^^^^^^^^^ method.defaultLibrary
// ^ punctuation
// ^ keyword
}
// ^ punctuation
}
// <- punctuation

@ -0,0 +1,53 @@
private virtual with sharing class Me {
// <- keyword
// ^ keyword
// ^^^^^^^^^^^^ keyword
// ^ keyword
// ^ class
// ^ punctuation
{
// ^ punctuation
update a;
// ^ function.defaultLibrary
// ^ variable
// ^ punctuation
insert a;
// ^ function.defaultLibrary
// ^ variable
// ^ punctuation
upsert a;
// ^ function.defaultLibrary
// ^ variable
// ^ punctuation
upsert a Account.Id;
// ^ function.defaultLibrary
// ^ variable
// ^ type
// ^ punctuation
// ^ type
// ^ punctuation
delete a;
// ^ function.defaultLibrary
// ^ variable
// ^ punctuation
delete a.Id;
// ^ function.defaultLibrary
// ^ type
// ^ punctuation
// ^ property
// ^ punctuation
undelete a.Id;
// ^ function.defaultLibrary
// ^ type
// ^ punctuation
// ^ property
// ^ punctuation
merge a b;
// ^ function.defaultLibrary
// ^ variable
// ^ variable
// ^ punctuation
}
// ^ punctuation
}
// <- punctuation

@ -0,0 +1,9 @@
public enum MyEnumClass { X, Y }
// <- keyword
// ^ keyword
// ^ enum
// ^ punctuation
// ^ enumMember
// ^ punctuation
// ^ enumMember
// ^ punctuation

@ -0,0 +1,34 @@
public class Me {
// <- keyword
// ^ keyword
// ^ class
// ^ punctuation
public enum Season {WINTER, SPRING, SUMMER, FALL}
// ^ keyword
// ^ keyword
// ^ enum
// ^ punctuation
// ^ enumMember
// ^ punctuation
// ^ enumMember
// ^ punctuation
// ^ enumMember
// ^ punctuation
// ^ enumMember
// ^ punctuation
{
//^ punctuation
Season s = Season.SPRING;
// ^ type
// ^ variable
// ^ operator
// ^ enum
// ^ punctuation
// ^ enumMember
// ^ punctuation
}
//^ punctuation
}
// <- punctuation

@ -0,0 +1,73 @@
public class Me {
// <- keyword
// ^ keyword
// ^ class
// ^ punctuation
{
// ^ punctuation
Account a = new Account(Name='Acme');
// ^ type
// ^ variable
// ^ operator
// ^ keyword
// ^ type
// ^ punctuation
// ^ variable
// ^ operator
// ^ string
// ^ punctuation
// ^ punctuation
try {
// ^ keyword
// ^ punctuation
insert a;
// ^ function.defaultLibrary
// ^ variable
// ^ punctuation
} catch(DmlException e) {
// ^ punctuation
// ^ keyword
// ^ punctuation
// ^ type
// ^ variable
// ^ punctuation
// ^ punctuation
// Process exception here
// ^^^^^^^^^^ comment
Boolean failed = true;
// ^ type
// ^ variable
// ^ operator
// ^ variable.readonly.defaultLibrary
// ^ punctuation
} catch(Exception e) {
// ^ punctuation
// ^ keyword
// ^ punctuation
// ^ type
// ^ variable
// ^ punctuation
// ^ punctuation
// Process exception here
Boolean failed = true;
// ^ type
// ^ variable
// ^ operator
// ^ variable.readonly.defaultLibrary
// ^ punctuation
} finally {
// ^ punctuation
// ^ keyword
// ^ punctuation
Boolean finallyRan = true;
// ^ type
// ^ variable
// ^ operator
// ^ variable.readonly.defaultLibrary
// ^ punctuation
}
// ^ punctuation
}
// ^ punctuation
}
// <- punctuation

@ -0,0 +1,27 @@
public class Me {{
// <- keyword
// ^ keyword
// ^ class
// ^ punctuation
// ^ punctuation
AccountTriggerhandler.seenRecordsMap = new Map<String, Set<Id>>();
// ^ type
// ^ punctuation
// ^ property
// ^ operator
// ^ keyword
// ^ type
// ^ punctuation
// ^ type
// ^ punctuation
// ^ type
// ^ punctuation
// ^ type
// ^ punctuation
// ^ punctuation
// ^ punctuation
// ^ punctuation
// ^ punctuation
} }
// <- punctuation
//^ punctuation

@ -0,0 +1,44 @@
public class Me {
// <- keyword
// ^ keyword
// ^ class
// ^ punctuation
{
// ^ punctuation
SObject a = new Account();
// ^ type
// ^ variable
// ^ operator
// ^ keyword
// ^ type
// ^ punctuation
// ^ punctuation
// ^ punctuation
if(a instanceof Account) {
// ^ keyword
// ^ punctuation
// ^ variable
// ^ keyword
// ^ type
// ^ punctuation
// ^ punctuation
Account p = (Account)a;
// ^ type
// ^ variable
// ^ operator
// ^ punctuation
// ^ type
// ^ punctuation
// ^ variable
// ^ punctuation
} else {
// ^ punctuation
// ^ keyword
// ^ punctuation
// something else...
}
// ^ punctuation
}
// ^ punctuation
}
// <- punctuation

@ -0,0 +1,14 @@
public virtual interface MyInterface {
// <- keyword
// ^ keyword
// ^ keyword
// ^ interface
// ^ punctuation
void myMethod();
//^ type.defaultLibrary
// ^ method
// ^ punctuation
// ^ punctuation
// ^ punctuation
}
// <- punctuation

@ -0,0 +1,10 @@
global class Me implements Interface1, Interface2 {}
// <- keyword
// ^ keyword
// ^ class
// ^ keyword
// ^ interface
// ^ punctuation
// ^ interface
// ^ punctuation
// ^ punctuation

@ -0,0 +1,78 @@
public class Me {
// <- keyword
// ^ keyword
// ^ class
// ^ punctuation
public void method1(String param1, Integer param2){
// ^ keyword
// ^ type.defaultLibrary
// ^ method
// ^ punctuation
// ^ type
// ^ parameter
// ^ punctuation
// ^ type
// ^ parameter
// ^ punctuation
// ^ punctuation
param1 = '1';
// ^ parameter
// ^ operator
// ^ string
// ^ punctuation
param2 = 2;
// ^ parameter
// ^ operator
// ^ number
// ^ punctuation
}
// ^ punctuation
global Integer method1(Integer param1){
// ^ keyword
// ^ type
// ^ method
// ^ punctuation
// ^ type
// ^ parameter
// ^ punctuation
// ^ punctuation
return param1;
// ^ keyword
// ^ parameter
// ^ punctuation
}
// ^ punctuation
public void helloWorld(final Integer i){
// ^ keyword
// ^ type.defaultLibrary
// ^ method
// ^ punctuation
// ^ keyword
// ^ type
// ^ parameter
// ^ punctuation
// ^ punctuation
System.debug(i);
// ^ type
// ^ punctuation
// ^ punctuation
// ^ parameter
// ^ punctuation
// ^ punctuation
}
// ^ punctuation
public testMethod void helloWorld(){
// ^ keyword
// ^ keyword
// ^ type.defaultLibrary
// ^ method
// ^ punctuation
// ^ punctuation
// ^ punctuation
System.debug(i);
}
// ^ punctuation
}
// <- punctuation

@ -0,0 +1,158 @@
public class TestObject2 {
// ^ keyword
// ^ keyword
// ^ class
// ^ punctuation
public Integer test1;
// ^ keyword
// ^ type
// ^ property
// ^ punctuation
private Integer test1;
// ^ keyword
// ^ type
// ^ property
// ^ punctuation
protected Integer test1;
// ^ keyword
// ^ type
// ^ property
// ^ punctuation
global Integer test1;
// ^ keyword
// ^ type
// ^ property
// ^ punctuation
Integer test1;
// ^ type
// ^ property
// ^ punctuation
final Integer test1;
// ^ keyword
// ^ type
// ^ property
// ^ punctuation
static Integer test1;
// ^ keyword
// ^ type
// ^ property
// ^ punctuation
transient Integer test1;
// ^ keyword
// ^ type
// ^ property
// ^ punctuation
static transient Integer test1;
// ^ keyword
// ^ keyword
// ^ type
// ^ property
// ^ punctuation
final static Integer test1;
// ^ keyword
// ^ keyword
// ^ type
// ^ variable.readonly
// ^ punctuation
public integer X { private get; set; }
// ^ keyword
// ^ type
// ^ property
// ^ punctuation
// ^ keyword
// ^ keyword
// ^ punctuation
// ^ keyword
// ^ punctuation
// ^ punctuation
global integer Y { get; public set; }
// ^ keyword
// ^ type
// ^ property
// ^ punctuation
// ^ keyword
// ^ punctuation
// ^ keyword
// ^ keyword
// ^ punctuation
// ^ punctuation
public integer Z { get; protected set; }
// ^ keyword
// ^ type
// ^ property
// ^ punctuation
// ^ keyword
// ^ punctuation
// ^ keyword
// ^ keyword
// ^ punctuation
// ^ punctuation
public integer prop {
// ^ keyword
// ^ type
// ^ property
// ^ punctuation
get { return prop; }
// ^ keyword
// ^ punctuation
// ^ keyword
// ^ property
// ^ punctuation
// ^ punctuation
set { prop = value; }
// ^ keyword
// ^ punctuation
// ^ property
// ^ operator
// ^ variable
// ^ punctuation
// ^ punctuation
}
// ^ punctuation
public integer prop {
// ^ keyword
// ^ type
// ^ property
// ^
get { return prop; }
// ^ keyword
// ^ punctuation
// ^ keyword
// ^ property
// ^ punctuation
// ^ punctuation
set;
// ^ keyword
// ^ punctuation
}
// ^ punctuation
private static final Integer TestConst = 10;
// ^ keyword
// ^ keyword
// ^ keyword
// ^ type
// ^ variable.readonly
// ^ operator
// ^ number
// ^ punctuation
{
// ^ punctuation
Integer i = TestConst;
// ^ type
// ^ variable
// ^ operator
// ^ variable.readonly
}
// ^ punctuation
}
// <- punctuation

@ -0,0 +1,272 @@
public class Me {
// <- keyword
// ^ keyword
// ^ class
// ^ punctuation
{
// ^ punctuation
List<Account> accs =
// ^ type
// ^ punctuation
// ^ type
// ^ punctuation
// ^ variable
// ^ operator
[SELECT Id FROM Account WHERE Name = :('x' + 'xx')];
// ^ punctuation
// ^ keyword
// ^ property
// ^ keyword
// ^ type
// ^ keyword
// ^ property
// ^ operator
// ^ punctuation
// ^ punctuation
// ^ string
// ^ operator
// ^ string
// ^ punctuation
// ^ punctuation
// ^ punctuation
List<Account> accs = [
// ^ type
// ^ punctuation
// ^ type
// ^ punctuation
// ^ variable
// ^ operator
// ^ punctuation
SELECT Id FROM Account
// ^ keyword
// ^ property
// ^ keyword
// ^ type
WHERE Name = :[SELECT Name FROM Account
// ^ keyword
// ^ property
// ^ operator
// ^ punctuation
// ^ punctuation
// ^ keyword
// ^ property
// ^ keyword
// ^ type
WHERE Id = :A.Id].Name];
// ^ keyword
// ^ property
// ^ operator
// ^ punctuation
// ^ type
// ^ punctuation
// ^ property
// ^ punctuation
// ^ punctuation
// ^ property
// ^ punctuation
// ^ punctuation
String name = [SELECT Name FROM Account
// ^ type
// ^ variable
// ^ operator
// ^ punctuation
// ^ keyword
// ^ property
// ^ keyword
// ^ type
WHERE Id = :A.Id][0].Name;
// ^ keyword
// ^ property
// ^ operator
// ^ punctuation
// ^ type
// ^ punctuation
// ^ property
// ^ punctuation
// ^ punctuation
// ^ number
// ^ punctuation
// ^ punctuation
// ^ property
// ^ punctuation
Integer cnt = [SELECT COUNT() FROM Contact ALL ROWS];
// ^ type
// ^ variable
// ^ operator
// ^ punctuation
// ^ keyword
// ^ function
// ^ punctuation
// ^ punctuation
// ^ keyword
// ^ type
// ^^^^^^^^ keyword
// ^ punctuation
// ^ punctuation
String a = 'A';
// ^ type
// ^ variable
// ^ operator
// ^ string
// ^ punctuation
List<Account> accs =
// ^ type
// ^ punctuation
// ^ type
// ^ punctuation
// ^ variable
// ^ operator
[SELECT Id FROM Account WHERE Name = :'N'+a+'M'+'E' AND Name = 'NOPE'];
// ^ punctuation
// ^ keyword
// ^ property
// ^ keyword
// ^ type
// ^ keyword
// ^ property
// ^ operator
// ^ punctuation
// ^ string
// ^ operator
// ^ variable
// ^ operator
// ^ string
// ^ operator
// ^ string
// ^ operator
// ^ property
// ^ operator
// ^ string
// ^ punctuation
// ^ punctuation
for(Account a : [SELECT Id FROM Account]){
// ^ keyword
// ^ punctuation
// ^ type
// ^ variable
// ^ punctuation
// ^ punctuation
// ^ keyword
// ^ property
// ^ keyword
// ^ type
// ^ punctuation
// ^ punctuation
// ^ punctuation
System.debug(a);
// ^ type
// ^ punctuation
// ^ method
// ^ punctuation
// ^ variable
// ^ punctuation
// ^ punctuation
}
// ^ punctuation
for(List<Account> accs : [SELECT Id FROM Account]){
// ^ keyword
// ^ punctuation
// ^ type
// ^ punctuation
// ^ type
// ^ punctuation
// ^ variable
// ^ punctuation
// ^ punctuation
// ^ keyword
// ^ property
// ^ keyword
// ^ type
// ^ punctuation
// ^ punctuation
// ^ punctuation
for(Account a : accs){
// ^ keyword
// ^ punctuation
// ^ type
// ^ variable
// ^ punctuation
// ^ variable
// ^ punctuation
// ^ punctuation
System.debug(a);
// ^ type
// ^ punctuation
// ^ method
// ^ punctuation
// ^ variable
// ^ punctuation
// ^ punctuation
}
// ^ punctuation
}
// ^ punctuation
List<List<SObject>> res =
// ^ type
// ^ punctuation
// ^ type
// ^ punctuation
// ^ type
// ^ punctuation
// ^ punctuation
// ^ variable
// ^ operator
[FIND :myString1 IN ALL FIELDS
// ^ punctuation
// ^ keyword
// ^ punctuation
// ^variable
// ^^^^^^^^^^^^^ keyword
RETURNING
// ^ keyword
Account (Id, Name WHERE Name LIKE :myString2
// ^ type
// ^ punctuation
// ^ property
// ^ punctuation
// ^ property
// ^ keyword
// ^ property
// ^ operator
// ^ punctuation
// ^ variable
LIMIT :myInt3),
// ^ keyword
// ^ punctuation
// ^ variable
Contact,
// ^ type
// ^ punctuation
Opportunity,
// ^ type
// ^ punctuation
Lead
// ^ type
WITH DIVISION =:myString4
// ^ keyword
// ^ keyword
// ^ operator
// ^ punctuation
// ^ variable
LIMIT :myInt5];
// ^ keyword
// ^ punctuation
// ^ variable
// ^ punctuation
// ^ punctuation
}
// ^ punctuation
}
// <- punctuation

@ -0,0 +1,230 @@
public class Me {
// <- keyword
// ^ keyword
// ^ class
// ^ punctuation
{
// ^ punctuation
Integer i = 0;
// ^ type
// ^ variable
// ^ operator
// ^ number
// ^ punctuation
switch on i {
// ^ keyword
// ^ keyword
// ^ variable
// ^ punctuation
when 2, 3, 4 {
// ^ keyword
// ^ number
// ^ punctuation
// ^ number
// ^ punctuation
// ^ number
// ^ punctuation
System.debug('when block 2');
// ^ type
// ^ punctuation
// ^ method
// ^ punctuation
// ^ string
// ^ punctuation
// ^ punctuation
}
// ^ punctuation
when null {
// ^ keyword
// ^ variable.readonly.defaultLibrary
// ^ punctuation
System.debug('bad integer');
// ^ type
// ^ punctuation
// ^ method
// ^ punctuation
// ^ string
// ^ punctuation
// ^ punctuation
}
// ^ punctuation
when else {
// ^ keyword
// ^ keyword
// ^ punctuation
System.debug('default ' + i);
// ^ type
// ^ punctuation
// ^ method
// ^ punctuation
// ^ string
// ^ operator
// ^ variable
// ^ punctuation
// ^ punctuation
}
// ^ punctuation
}
// ^ punctuation
switch on someInteger(i) {
// ^ keyword
// ^ keyword
// ^ method
// ^ punctuation
// ^ variable
// ^ punctuation
// ^ punctuation
when 2 {
// ^ keyword
// ^ number
// ^ punctuation
System.debug('when block 2');
// ^ type
// ^ punctuation
// ^ method
// ^ punctuation
// ^ string
// ^ punctuation
// ^ punctuation
}
// ^ punctuation
when else {
// ^ keyword
// ^ keyword
// ^ punctuation
System.debug('default');
// ^ type
// ^ punctuation
// ^ method
// ^ punctuation
// ^ string
// ^ punctuation
// ^ punctuation
}
// ^ punctuation
}
// ^ punctuation
SObject s = new Account();
// ^ type
// ^ variable
// ^ operator
// ^ keyword
// ^ type
// ^ punctuation
// ^ punctuation
// ^ punctuation
switch on s {
// ^ keyword
// ^ keyword
// ^ variable
// ^ punctuation
when Account a {
// ^ keyword
// ^ type
// ^ variable
// ^ punctuation
System.debug('account ' + a);
// ^ type
// ^ punctuation
// ^ method
// ^ punctuation
// ^ string
// ^ operator
// ^ variable
// ^ punctuation
// ^ punctuation
}
// ^ punctuation
when Contact c {
// ^ keyword
// ^ type
// ^ variable
// ^ punctuation
System.debug('contact ' + c);
// ^ type
// ^ punctuation
// ^ method
// ^ punctuation
// ^ string
// ^ operator
// ^ variable
// ^ punctuation
// ^ punctuation
}
// ^ punctuation
when else {
// ^ keyword
// ^ keyword
// ^ punctuation
System.debug('default');
// ^ type
// ^ punctuation
// ^ method
// ^ punctuation
// ^ string
// ^ punctuation
// ^ punctuation
}
// ^ punctuation
}
// ^ punctuation
switch on season {
// ^ keyword
// ^ keyword
// ^ variable
// ^ punctuation
when WINTER { // TODO: would be nice if it understood it was an enumMember
// ^ keyword
// ^ enumMember
// ^ punctuation
System.debug('boots');
// ^ type
// ^ punctuation
// ^ method
// ^ punctuation
// ^ string
// ^ punctuation
// ^ punctuation
}
// ^ punctuation
when SPRING, SUMMER {
// ^ keyword
// ^ enumMember
// ^ punctuation
// ^ enumMember
// ^ punctuation
System.debug('sandals');
// ^ type
// ^ punctuation
// ^ method
// ^ punctuation
// ^ string
// ^ punctuation
// ^ punctuation
}
// ^ punctuation
when else {
// ^ keyword
// ^ keyword
// ^ punctuation
System.debug('none of the above');
// ^ type
// ^ punctuation
// ^ method
// ^ punctuation
// ^ string
// ^ punctuation
// ^ punctuation
}
// ^ punctuation
}
// ^ punctuation
}
// ^ punctuation
}
// <- punctuation

@ -0,0 +1,36 @@
trigger myAccountTrigger on Account (
// <- keyword
// ^ type
// ^ keyword
// ^ type
// ^ punctuation
before insert,
// ^^^^^^^^^^^^^ keyword
// ^ punctuation
before update,
// ^^^^^^^^^^^^^ keyword
// ^ punctuation
before delete,
// ^^^^^^^^^^^^^ keyword
// ^ punctuation
after insert,
// ^^^^^^^^^^^^ keyword
// ^ punctuation
after update,
// ^^^^^^^^^^^^ keyword
// ^ punctuation
after delete,
// ^^^^^^^^^^^^ keyword
// ^ punctuation
after undelete) {
// ^^^^^^^^^^^^^^ keyword
// ^ punctuation
// ^ punctuation
Integer i = 1;
// ^ type
// ^ variable
// ^ operator
// ^ number
// ^ punctuation
}
// <- punctuation

@ -0,0 +1,186 @@
public class Me {
// <- keyword
// ^ keyword
// ^ class
// ^ punctuation
{
//^ punctuation
List<Integer> ints = new List<Integer>();
// ^ type
// ^ punctuation
// ^ type
// ^ punctuation
// ^ variable
// ^ operator
// ^ keyword
// ^ type
// ^ punctuation
// ^ type
// ^ punctuation
// ^ punctuation
// ^ punctuation
// ^ punctuation
List<Integer> ints = new List<Integer>{1,2,3};
// ^ type
// ^ punctuation
// ^ type
// ^ punctuation
// ^ variable
// ^ operator
// ^ keyword
// ^ type
// ^ punctuation
// ^ type
// ^ punctuation
// ^ punctuation
// ^ number
// ^ punctuation
// ^ number
// ^ punctuation
// ^ number
// ^ punctuation
// ^ punctuation
List<Integer> ints = new Integer[0];
// ^ type
// ^ punctuation
// ^ type
// ^ punctuation
// ^ variable
// ^ operator
// ^ keyword
// ^ type
// ^ punctuation
// ^ number
// ^ punctuation
// ^ punctuation
List<Integer> ints = new Integer[]{1,2,3};
// ^ type
// ^ punctuation
// ^ type
// ^ punctuation
// ^ variable
// ^ operator
// ^ keyword
// ^ type
Integer[] ints = new Integer[0];
// ^ type
// ^ punctuation
// ^ punctuation
// ^ variable
// ^ operator
// ^ keyword
// ^ type
// ^ punctuation
// ^ number
// ^ punctuation
// ^ punctuation
Set<Integer> ints = new Set<Integer>();
// ^ type
// ^ punctuation
// ^ type
// ^ punctuation
// ^ variable
// ^ operator
// ^ keyword
// ^ type
// ^ punctuation
// ^ type
// ^ punctuation
// ^ punctuation
// ^ punctuation
// ^ punctuation
Set<Integer> ints = new Set<Integer>{1,2,3};
// ^ type
// ^ punctuation
// ^ type
// ^ punctuation
// ^ variable
// ^ operator
// ^ keyword
// ^ type
// ^ punctuation
// ^ type
// ^ punctuation
// ^ punctuation
// ^ number
// ^ punctuation
// ^ number
// ^ punctuation
// ^ number
// ^ punctuation
// ^ punctuation
Map<String,Integer> intsBymap = new Map<String,Integer>();
// ^ type
// ^ punctuation
// ^ type
// ^ punctuation
// ^ type
// ^ punctuation
// ^ variable
// ^ operator
// ^ keyword
// ^ type
// ^ punctuation
// ^ type
// ^ punctuation
// ^ type
// ^ punctuation
// ^ punctuation
// ^ punctuation
// ^ punctuation
Map<String,Integer> intsBymap = new Map<String,Integer>{'hello' => 1, 'world' => 2};
// ^ type
// ^ punctuation
// ^ type
// ^ punctuation
// ^ type
// ^ punctuation
// ^ variable
// ^ operator
// ^ keyword
// ^ type
// ^ punctuation
// ^ type
// ^ punctuation
// ^ type
// ^ punctuation
// ^ punctuation
// ^ string
// ^^ operator
// ^ number
// ^ punctuation
// ^string
// ^^ operator
// ^ number
// ^ punctuation
// ^ punctuation
Integer i,j,k;
// ^ type
// ^ variable
// ^ punctuation
// ^ variable
// ^ punctuation
// ^ variable
// punctuation
Integer i = 0, j, k = 1;
// ^ type
// ^ variable
// ^ operator
// ^ number
// ^ punctuation
// ^ variable
// ^ punctuation
// ^ variable
// ^ operator
// ^ number
// ^ punctuation
}
//^ punctuation
}
// <- punctuation

@ -0,0 +1,14 @@
public class Me {
// ^ definition.class
{
Database.insert(null);
// ^^^^^^ reference.call
You y = new You();
// ^ reference.class
// ^^^ reference.class
y.method1();
// ^ reference.call
}
}

@ -0,0 +1,2 @@
public class Me {}
// ^ definition.class

@ -0,0 +1,4 @@
public enum Enum1 {
// ^ definition.enum
Val1, Val2, Val3
}

@ -0,0 +1,4 @@
public interface Test1 {
// ^ definition.interface
void testMethod(String param1);
}

@ -0,0 +1,3 @@
public class Hello implements Test1 {}
// ^ definition.class
// ^ reference.implementation

@ -0,0 +1,27 @@
global class ParentClass {
// ^ definition.class
private String method1(Integer i){
// ^ definition.method
return i;
}
public class InnerClass1 {
// ^ definition.class
public void innerMethod1(){}
// ^ definition.method
private void innerMethod2(){}
// ^ definition.method
}
private class InnerClass2 {
// ^ definition.class
public void innerMethod1(){}
// ^ definition.method
private void innerMethod3(){}
// ^ definition.method
}
}

@ -0,0 +1,21 @@
{
"targets": [
{
"target_name": "tree_sitter_sfapex_binding",
"include_dirs": [
"<!(node -e \"require('nan')\")",
"apex/src"
],
"sources": [
"apex/src/parser.c",
"soql/src/parser.c",
"sosl/src/parser.c",
"bindings/node/binding.cc",
# If your language uses an external scanner, add it here.
],
"cflags_c": [
"-std=c99",
]
}
]
}

@ -0,0 +1 @@
module.exports = require("./index").then((val) => val.apex);

@ -0,0 +1,51 @@
#include "tree_sitter/parser.h"
#include <node.h>
#include "nan.h"
using namespace v8;
extern "C" TSLanguage * tree_sitter_apex();
extern "C" TSLanguage * tree_sitter_soql();
extern "C" TSLanguage * tree_sitter_sosl();
namespace {
NAN_METHOD(New) {}
void Init(Local<Object> exports, Local<Object> module) {
// Apex
Local<FunctionTemplate> apex_tpl = Nan::New<FunctionTemplate>(New);
apex_tpl->SetClassName(Nan::New("Language").ToLocalChecked());
apex_tpl->InstanceTemplate()->SetInternalFieldCount(1);
Local<Function> apex_constructor = Nan::GetFunction(apex_tpl).ToLocalChecked();
Local<Object> apex_instance = apex_constructor->NewInstance(Nan::GetCurrentContext()).ToLocalChecked();
Nan::SetInternalFieldPointer(apex_instance, 0, tree_sitter_apex());
Nan::Set(apex_instance, Nan::New("name").ToLocalChecked(), Nan::New("apex").ToLocalChecked());
// SOQL
Local<FunctionTemplate> soql_tpl = Nan::New<FunctionTemplate>(New);
soql_tpl->SetClassName(Nan::New("Language").ToLocalChecked());
soql_tpl->InstanceTemplate()->SetInternalFieldCount(1);
Local<Function> soql_constructor = Nan::GetFunction(soql_tpl).ToLocalChecked();
Local<Object> soql_instance = soql_constructor->NewInstance(Nan::GetCurrentContext()).ToLocalChecked();
Nan::SetInternalFieldPointer(soql_instance, 0, tree_sitter_soql());
Nan::Set(soql_instance, Nan::New("name").ToLocalChecked(), Nan::New("soql").ToLocalChecked());
// SOSL
Local<FunctionTemplate> sosl_tpl = Nan::New<FunctionTemplate>(New);
sosl_tpl->SetClassName(Nan::New("Language").ToLocalChecked());
sosl_tpl->InstanceTemplate()->SetInternalFieldCount(1);
Local<Function> sosl_constructor = Nan::GetFunction(sosl_tpl).ToLocalChecked();
Local<Object> sosl_instance = sosl_constructor->NewInstance(Nan::GetCurrentContext()).ToLocalChecked();
Nan::SetInternalFieldPointer(sosl_instance, 0, tree_sitter_sosl());
Nan::Set(sosl_instance, Nan::New("name").ToLocalChecked(), Nan::New("sosl").ToLocalChecked());
Nan::Set(exports, Nan::New("apex").ToLocalChecked(), apex_instance);
Nan::Set(exports, Nan::New("soql").ToLocalChecked(), soql_instance);
Nan::Set(exports, Nan::New("sosl").ToLocalChecked(), sosl_instance);
}
NODE_MODULE(tree_sitter_sfapex_binding, Init)
} // namespace

@ -0,0 +1,46 @@
let exportedValues = {};
try {
exportedValues = require("../../build/Release/tree_sitter_sfapex_binding");
} catch (errorA) {
if (errorA.code !== "MODULE_NOT_FOUND") {
throw errorA;
}
try {
exportedValues = require("../../build/Debug/tree_sitter_sfapex_binding");
} catch (errorB) {
if (errorB.code !== "MODULE_NOT_FOUND") {
throw errorB;
}
// TODO: load WASM instead?? Not sure how to make it hot-swappable
// but leaving it async load to leave the door open
// exportedValues = getWasmModules();
throw errorA;
}
}
// Eventually, should be able to load the WASM module as a direct swap for the native... life goal
async function getWasmModules() {
const TreeSitter = require(__dirname +
"/../../prebuilds/wasm/tree-sitter.js");
await TreeSitter.init();
return {
apex: await TreeSitter.Language.load(
__dirname + "/../../prebuilds/wasm/tree-sitter-apex.wasm"
),
soql: await TreeSitter.Language.load(
__dirname + "/../../prebuilds/wasm/tree-sitter-soql.wasm"
),
sosl: await TreeSitter.Language.load(
__dirname + "/../../prebuilds/wasm/tree-sitter-sosl.wasm"
),
};
}
module.exports = Promise.resolve(exportedValues).then((mod) => {
try {
mod.apex.nodeTypeInfo = require("../../apex/src/node-types.json");
mod.soql.nodeTypeInfo = require("../../soql/src/node-types.json");
mod.sosl.nodeTypeInfo = require("../../sosl/src/node-types.json");
} catch (_) {}
return mod;
});

@ -0,0 +1 @@
module.exports = require("./index").then((val) => val.soql);

@ -0,0 +1 @@
module.exports = require("./index").then((val) => val.sosl);

@ -0,0 +1,40 @@
fn main() {
let src_dir = std::path::Path::new("src");
let mut c_config = cc::Build::new();
c_config.include(&src_dir);
c_config
.flag_if_supported("-Wno-unused-parameter")
.flag_if_supported("-Wno-unused-but-set-variable")
.flag_if_supported("-Wno-trigraphs");
let parser_path = src_dir.join("parser.c");
c_config.file(&parser_path);
// If your language uses an external scanner written in C,
// then include this block of code:
/*
let scanner_path = src_dir.join("scanner.c");
c_config.file(&scanner_path);
println!("cargo:rerun-if-changed={}", scanner_path.to_str().unwrap());
*/
c_config.compile("parser");
println!("cargo:rerun-if-changed={}", parser_path.to_str().unwrap());
// If your language uses an external scanner written in C++,
// then include this block of code:
/*
let mut cpp_config = cc::Build::new();
cpp_config.cpp(true);
cpp_config.include(&src_dir);
cpp_config
.flag_if_supported("-Wno-unused-parameter")
.flag_if_supported("-Wno-unused-but-set-variable");
let scanner_path = src_dir.join("scanner.cc");
cpp_config.file(&scanner_path);
cpp_config.compile("scanner");
println!("cargo:rerun-if-changed={}", scanner_path.to_str().unwrap());
*/
}

@ -0,0 +1,52 @@
//! This crate provides SF_SOQL language support for the [tree-sitter][] parsing library.
//!
//! Typically, you will use the [language][language func] function to add this language to a
//! tree-sitter [Parser][], and then use the parser to parse some code:
//!
//! ```
//! let code = "";
//! let mut parser = tree_sitter::Parser::new();
//! parser.set_language(tree_sitter_SF_SOQL::language()).expect("Error loading SF_SOQL grammar");
//! let tree = parser.parse(code, None).unwrap();
//! ```
//!
//! [Language]: https://docs.rs/tree-sitter/*/tree_sitter/struct.Language.html
//! [language func]: fn.language.html
//! [Parser]: https://docs.rs/tree-sitter/*/tree_sitter/struct.Parser.html
//! [tree-sitter]: https://tree-sitter.github.io/
use tree_sitter::Language;
extern "C" {
fn tree_sitter_SF_SOQL() -> Language;
}
/// Get the tree-sitter [Language][] for this grammar.
///
/// [Language]: https://docs.rs/tree-sitter/*/tree_sitter/struct.Language.html
pub fn language() -> Language {
unsafe { tree_sitter_SF_SOQL() }
}
/// The content of the [`node-types.json`][] file for this grammar.
///
/// [`node-types.json`]: https://tree-sitter.github.io/tree-sitter/using-parsers#static-node-types
pub const NODE_TYPES: &'static str = include_str!("../../src/node-types.json");
// Uncomment these to include any queries that this grammar contains
// pub const HIGHLIGHTS_QUERY: &'static str = include_str!("../../queries/highlights.scm");
// pub const INJECTIONS_QUERY: &'static str = include_str!("../../queries/injections.scm");
// pub const LOCALS_QUERY: &'static str = include_str!("../../queries/locals.scm");
// pub const TAGS_QUERY: &'static str = include_str!("../../queries/tags.scm");
#[cfg(test)]
mod tests {
#[test]
fn test_can_load_grammar() {
let mut parser = tree_sitter::Parser::new();
parser
.set_language(super::language())
.expect("Error loading SF_SOQL language");
}
}

@ -0,0 +1,6 @@
type Parser = import("web-tree-sitter");
declare module "web-tree-sitter-sfapex" {
function getApexParser(): Promise<Parser>;
function getSoqlParser(): Promise<Parser>;
function getSoslParser(): Promise<Parser>;
}

@ -0,0 +1,42 @@
const Parser = require("web-tree-sitter");
const fs = require("fs");
function getApexParser() {
return getParser(__dirname + "/tree-sitter-apex.wasm");
}
function getSoqlParser() {
return getParser(__dirname + "/tree-sitter-soql.wasm");
}
function getSoslParser() {
return getParser(__dirname + "/tree-sitter-sosl.wasm");
}
/**
* @param {string} wasmLangFile
* @returns {Promise<Parser>}
*/
async function getParser(wasmLangFile) {
return new Promise(async (resolve, reject) => {
await Parser.init();
// make loadable on NodeJS to enable testing, should be smarter later
const parser = new Parser();
fs.readFile(wasmLangFile, async (err, data) => {
if (err) {
reject(err);
}
try {
const lang = await Parser.Language.load(data);
parser.setLanguage(lang);
resolve(parser);
} catch (err2) {
reject(err2);
}
});
});
}
module.exports = {
getApexParser,
getSoqlParser,
getSoslParser,
};

@ -0,0 +1,21 @@
{
"name": "web-tree-sitter-sfapex",
"version": "0.0.9-beta2",
"lockfileVersion": 3,
"requires": true,
"packages": {
"": {
"name": "web-tree-sitter-sfapex",
"version": "0.0.9-beta2",
"license": "ISC",
"dependencies": {
"web-tree-sitter": "^0.20.8"
}
},
"node_modules/web-tree-sitter": {
"version": "0.20.8",
"resolved": "https://registry.npmjs.org/web-tree-sitter/-/web-tree-sitter-0.20.8.tgz",
"integrity": "sha512-weOVgZ3aAARgdnb220GqYuh7+rZU0Ka9k9yfKtGAzEYMa6GgiCzW9JjQRJyCJakvibQW+dfjJdihjInKuuCAUQ=="
}
}
}

@ -0,0 +1,15 @@
{
"name": "web-tree-sitter-sfapex",
"version": "0.0.9",
"description": "tree-sitter-sfapex WASM",
"main": "index.js",
"types": "index.d.ts",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
},
"author": "Anthony Heber",
"license": "ISC",
"dependencies": {
"web-tree-sitter": "^0.20.8"
}
}

@ -0,0 +1,33 @@
const dialects = { SOQL: "soql", SOSL: "sosl", APEX: "apex" };
function createCaseInsensitiveRegex(word) {
return new RegExp(
word
.split("")
.map((letter) => `[${letter.toLowerCase()}${letter.toUpperCase()}]`)
.join("")
);
}
function ci(keyword) {
const words = keyword.split(" ");
const regExps = words.map(createCaseInsensitiveRegex);
return regExps.length == 1
? alias(regExps[0], keyword)
: alias(seq(...regExps), keyword.replace(/ /g, "_"));
}
function commaJoined(expression) {
return optional(commaJoined1(expression));
}
function commaJoined1(expression) {
return joined(",", expression);
}
function joined(joinedBy, expression) {
return seq(expression, repeat(seq(joinedBy, expression)));
}
module.exports = { ci, commaJoined, commaJoined1, joined, dialects };

@ -0,0 +1,458 @@
const { ci, commaJoined1, joined, dialects } = require("./common.js");
module.exports = function defineGrammar(dialect) {
return {
/*
RESOURCES
https://blog.jeffdouglas.com/2009/09/23/syntax-rules-for-soql/
https://github.com/forcedotcom/apex-tmLanguage
https://developer.salesforce.com/docs/atlas.en-us.238.0.soql_sosl.meta/soql_sosl/sforce_api_calls_soql_sosl_intro.htm
*/
conflicts: ($) => [[$.function_name, $.count_expression]],
rules: {
_soql_query_expression: ($) => $.soql_query_body,
subquery: ($) => seq("(", $.soql_query_body, ")"),
soql_query_body: ($) => {
s = [
$.select_clause,
$.from_clause,
optional(alias($.soql_using_clause, $.using_clause)),
optional($.where_clause),
optional(alias($.soql_with_clause, $.with_clause)),
optional($.group_by_clause),
optional($.order_by_clause),
optional($.limit_clause),
optional($.offset_clause),
optional($.for_clause),
optional($.update_clause),
];
if (dialect == dialects.APEX) {
s.push(optional($.all_rows_clause));
}
return seq(...s);
},
count_expression: ($) =>
seq(alias(ci("COUNT"), $.function_name), "(", ")"),
// SELECT
select_clause: ($) =>
seq(
ci("SELECT"),
choice($.count_expression, commaJoined1($._selectable_expression))
),
_selectable_expression: ($) =>
choice(
$._value_expression,
$.alias_expression,
$.type_of_clause,
$.fields_expression,
$.subquery
),
// USING SCOPE
soql_using_clause: ($) => seq(ci("USING SCOPE"), $.using_scope_type),
using_scope_type: ($) =>
choice(
ci("delegated"),
ci("everything"),
ci("mine"),
ci("mine_and_my_groups"),
ci("my_territory"),
ci("my_team_territory"),
ci("team")
),
// TYPE OF
type_of_clause: ($) =>
seq(
ci("TYPEOF"),
$.identifier,
repeat($.when_expression),
optional($.else_expression),
ci("END")
),
when_expression: ($) =>
seq(ci("WHEN"), $.identifier, ci("THEN"), $.field_list),
else_expression: ($) => seq(ci("ELSE"), $.field_list),
// GROUP BY
group_by_clause: ($) =>
seq(ci("GROUP BY"), $._group_by_expression, optional($.having_clause)),
_group_by_expression: ($) =>
choice(
commaJoined1(choice($.field_identifier, $.function_expression)),
seq(
choice(
alias(ci("ROLLUP"), $.function_name),
alias(ci("CUBE"), $.function_name)
),
"(",
commaJoined1($.field_identifier),
")"
)
),
// FOR
for_clause: ($) => seq(ci("FOR"), commaJoined1($.for_type)),
for_type: ($) => choice(ci("UPDATE"), ci("REFERENCE"), ci("VIEW")),
// GROUP BY HAVING
having_clause: ($) => seq(ci("HAVING"), $._having_boolean_expression),
_having_boolean_expression: ($) =>
choice(
$.having_and_expression,
$.having_or_expression,
$.having_not_expression,
$._having_condition_expression
),
having_and_expression: ($) =>
seq(
$._having_condition_expression,
repeat1(seq(ci("AND"), $._having_condition_expression))
),
having_or_expression: ($) =>
seq(
$._having_condition_expression,
repeat1(seq(ci("OR"), $._having_condition_expression))
),
having_not_expression: ($) =>
seq(ci("NOT"), $._having_condition_expression),
_having_condition_expression: ($) =>
choice(
seq("(", $._having_boolean_expression, ")"),
$.having_comparison_expression
),
having_comparison_expression: ($) =>
seq($.function_expression, $._having_comparison),
_having_comparison: ($) =>
choice($._having_value_comparison, $._having_set_comparison),
_having_value_comparison: ($) =>
seq(
$.value_comparison_operator,
choice($._soql_literal, $.bound_apex_expression)
),
_having_set_comparison: ($) =>
seq(
$.set_comparison_operator,
choice(
seq(
"(",
commaJoined1(choice($._soql_literal, $.bound_apex_expression)),
")"
),
$.bound_apex_expression
)
),
from_clause: ($) =>
seq(
ci("FROM"),
commaJoined1(choice($.storage_identifier, $.storage_alias))
),
storage_identifier: ($) => choice($.identifier, $.dotted_identifier),
storage_alias: ($) =>
seq($.storage_identifier, optional(ci("AS")), $.identifier),
// FIELDS
fields_expression: ($) => seq(ci("FIELDS"), "(", $.fields_type, ")"),
fields_type: ($) => choice(ci("ALL"), ci("CUSTOM"), ci("STANDARD")),
// WHERE
where_clause: ($) => seq(ci("WHERE"), $._boolean_expression),
_boolean_expression: ($) =>
choice(
$.and_expression,
$.or_expression,
$.not_expression,
$._condition_expression
),
and_expression: ($) =>
seq(
$._condition_expression,
repeat1(seq(ci("AND"), $._condition_expression))
),
or_expression: ($) =>
seq(
$._condition_expression,
repeat1(seq(ci("OR"), $._condition_expression))
),
not_expression: ($) => seq(ci("NOT"), $._condition_expression),
_condition_expression: ($) =>
choice(seq("(", $._boolean_expression, ")"), $.comparison_expression),
comparison_expression: ($) => seq($._value_expression, $._comparison),
_comparison: ($) => choice($._value_comparison, $._set_comparison),
_value_comparison: ($) =>
seq(
$.value_comparison_operator,
choice($._soql_literal, $.bound_apex_expression)
),
_set_comparison: ($) =>
seq(
$.set_comparison_operator,
choice(
$.subquery,
seq(
"(",
commaJoined1(choice($._soql_literal, $.bound_apex_expression)),
")"
),
$.bound_apex_expression
)
),
// WITH
soql_with_clause: ($) =>
seq(ci("WITH"), alias($.soql_with_type, $.with_type)),
// WITH
soql_with_type: ($) =>
choice(
ci("Security_Enforced"),
ci("User_Mode"),
ci("System_Mode"),
$.with_record_visibility_expression,
$.with_data_cat_expression,
$.with_user_id_type
),
with_user_id_type: ($) => seq(ci("UserId"), "=", $.string_literal),
// WITH RecordVisibilityContext
with_record_visibility_expression: ($) =>
seq(
ci("RecordVisibilityContext"),
"(",
commaJoined1($.with_record_visibility_param),
")"
),
with_record_visibility_param: ($) =>
choice(
seq(ci("maxDescriptorPerRecord"), "=", $.int),
seq(ci("supportsDomains"), "=", $.boolean),
seq(ci("supportsDelegates"), "=", $.boolean)
),
// WITH DATA CATEGORY
with_data_cat_expression: ($) =>
seq(ci("DATA CATEGORY"), joined(ci("AND"), $.with_data_cat_filter)),
with_data_cat_filter: ($) =>
seq(
$.identifier,
$.with_data_cat_filter_type,
choice($.identifier, seq("(", commaJoined1($.identifier), ")"))
),
with_data_cat_filter_type: ($) =>
choice(ci("AT"), ci("ABOVE"), ci("BELOW"), ci("ABOVE_OR_BELOW")),
// LIMIT
limit_clause: ($) =>
seq(ci("LIMIT"), choice($.int, $.bound_apex_expression)),
// OFFSET
offset_clause: ($) =>
seq(ci("OFFSET"), choice($.int, $.bound_apex_expression)),
update_clause: ($) => seq(ci("UPDATE"), commaJoined1($.update_type)),
update_type: ($) => choice(ci("TRACKING"), ci("VIEWSTAT")),
alias_expression: ($) =>
seq($._value_expression, optional(ci("AS")), $.identifier),
// ORDER BY
order_by_clause: ($) =>
seq(ci("ORDER BY"), commaJoined1($.order_expression)),
order_expression: ($) =>
seq(
$._value_expression,
optional($.order_direction),
optional($.order_null_direciton)
),
order_direction: ($) => choice(ci("ASC"), ci("DESC")),
order_null_direciton: ($) => choice(ci("NULLS FIRST"), ci("NULLS LAST")),
geo_location_type: ($) =>
choice(
$.field_identifier,
$.bound_apex_expression,
seq(
alias(ci("GEOLOCATION"), $.function_name),
"(",
$.decimal,
",",
$.decimal,
")"
)
),
_value_expression: ($) =>
choice($.function_expression, $.field_identifier),
function_expression: ($) =>
choice(
seq(
alias(ci("DISTANCE"), $.function_name),
"(",
choice($.field_identifier, $.bound_apex_expression),
",",
$.geo_location_type,
",",
$.string_literal,
")"
),
seq($.function_name, "(", $._value_expression, ")")
),
dotted_identifier: ($) =>
seq($.identifier, repeat1(seq(".", $.identifier))),
field_identifier: ($) => choice($.identifier, $.dotted_identifier),
field_list: ($) =>
seq(commaJoined1(choice($.identifier, $.dotted_identifier))),
all_rows_clause: ($) => ci("ALL ROWS"),
boolean: ($) => choice(ci("TRUE"), ci("FALSE")),
value_comparison_operator: ($) =>
choice("=", "!=", "<>", "<", "<=", ">", ">=", ci("LIKE")),
set_comparison_operator: ($) =>
choice(ci("IN"), seq(ci("NOT IN")), ci("INCLUDES"), ci("EXCLUDES")),
date_literal: ($) =>
choice(
ci("YESTERDAY"),
ci("TODAY"),
ci("TOMORROW"),
ci("LAST_WEEK"),
ci("THIS_WEEK"),
ci("NEXT_WEEK"),
ci("LAST_MONTH"),
ci("THIS_MONTH"),
ci("NEXT_MONTH"),
ci("LAST_90_DAYS"),
ci("NEXT_90_DAYS"),
ci("THIS_QUARTER"),
ci("LAST_QUARTER"),
ci("NEXT_QUARTER"),
ci("THIS_YEAR"),
ci("LAST_YEAR"),
ci("NEXT_YEAR"),
ci("THIS_FISCAL_QUARTER"),
ci("LAST_FISCAL_QUARTER"),
ci("NEXT_FISCAL_QUARTER"),
ci("THIS_FISCAL_YEAR"),
ci("LAST_FISCAL_YEAR"),
ci("NEXT_FISCAL_YEAR")
),
date_literal_with_param: ($) =>
seq(
alias(
token(
choice(
ci("LAST_N_DAYS"),
ci("NEXT_N_DAYS"),
ci("N_DAYS_AGO"),
ci("NEXT_N_WEEKS"),
ci("LAST_N_WEEKS"),
ci("N_WEEKS_AGO"),
ci("NEXT_N_MONTHS"),
ci("LAST_N_MONTHS"),
ci("N_MONTHS_AGO"),
ci("NEXT_N_QUARTERS"),
ci("LAST_N_QUARTERS"),
ci("N_QUARTERS_AGO"),
ci("NEXT_N_YEARS"),
ci("LAST_N_YEARS"),
ci("N_YEARS_AGO"),
ci("NEXT_N_FISCAL_QUARTERS"),
ci("LAST_N_FISCAL_QUARTERS"),
ci("N_FISCAL_QUARTERS_AGO"),
ci("NEXT_N_FISCAL_YEARS"),
ci("LAST_N_FISCAL_YEARS"),
ci("N_FISCAL_YEARS_AGO")
)
),
$.date_literal
),
":",
$.int
),
// Not all valid for SOSL
function_name: ($) =>
choice(
ci("AVG"),
ci("COUNT"),
ci("COUNT_DISTINCT"),
ci("MIN"),
ci("MAX"),
ci("SUM"),
ci("GROUPING"),
ci("FORMAT"),
ci("convertCurrency"),
ci("toLabel"),
ci("CALENDAR_MONTH"),
ci("CALENDAR_QUARTER"),
ci("CALENDAR_YEAR"),
ci("DAY_IN_MONTH"),
ci("DAY_IN_WEEK"),
ci("DAY_IN_YEAR"),
ci("DAY_ONLY"),
ci("FISCAL_MONTH"),
ci("FISCAL_QUARTER"),
ci("FISCAL_YEAR"),
ci("HOUR_IN_DAY"),
ci("WEEK_IN_MONTH"),
ci("WEEK_IN_YEAR")
),
apex_method_identifier: ($) => seq($.identifier, seq("(", ")")),
apex_identifier: ($) =>
joined(
seq(optional("?"), "."),
choice($.identifier, $.apex_method_identifier)
),
bound_apex_expression: ($) => {
if (dialect == dialects.APEX) {
return seq(":", $.expression); // defined in Apex rules
} else {
return "**DONOTMATCHEVER**";
}
},
null_literal: ($) => ci("NULL"),
_soql_literal: ($) =>
choice(
$.int,
$.decimal,
$.string_literal,
$.date,
$.date_time,
$.boolean,
$.date_literal,
$.date_literal_with_param,
$.currency_literal,
$.null_literal
),
string_literal: ($) => /'(\\[nNrRtTbBfFuU"'_%\\]|[^\\'])*'/,
int: ($) => /\d+/,
decimal: ($) => /-?\d+(\.\d+)?/,
date: ($) =>
/[1-4][0-9]{3}-(?:0[1-9]|1[0-2])-(?:[0-2][1-9]|[1-2]0|3[0-1])/,
date_time: ($) =>
/[1-4][0-9]{3}-(?:0[1-9]|1[0-2])-(?:[0-2][1-9]|[1-2]0|3[0-1])T([0-1]\d|2[0-3]):[0-5]\d:[0-5]\d(?:\.\d\d?\d?)?(?:Z|[+-][0-1]\d:[0-5]\d)/,
currency_literal: ($) => /\w{3}\d+(\.\d+)?/,
identifier: ($) => /[A-Za-z][A-Za-z\d_]*/,
},
};
};

@ -0,0 +1,112 @@
const { ci, commaJoined1, dialects } = require("./common");
module.exports = function defineGrammar(dialect) {
const soqlGrammar = require("./soql-grammar")(dialect);
return {
/*
RESOURCES
https://github.com/forcedotcom/apex-tmLanguage
https://developer.salesforce.com/docs/atlas.en-us.238.0.soql_sosl.meta/soql_sosl/sforce_api_calls_soql_sosl_intro.htm
*/
conflicts: soqlGrammar.conflicts,
rules: {
_query_expression: ($) => $.sosl_query_body,
sosl_query_body: ($) =>
seq(
$.find_clause,
optional($.in_clause),
optional(repeat($.returning_clause)),
optional(repeat(alias($.sosl_with_clause, $.with_clause))),
optional($.limit_clause),
optional($.offset_clause),
optional($.update_clause)
),
// FIND
find_clause: ($) =>
seq(
ci("FIND"),
choice(
$.bound_apex_expression,
seq($.term_separator_start, $.term, $.term_separator_end)
)
),
in_clause: ($) => seq(ci("IN"), $.in_type, ci("FIELDS")),
in_type: ($) =>
choice(ci("ALL"), ci("EMAIL"), ci("NAME"), ci("PHONE"), ci("SIDEBAR")),
term_separator_start: ($) => (dialect == dialects.SOSL ? "{" : "'"),
term_separator_end: ($) => (dialect == dialects.SOSL ? "}" : "'"),
term: ($) => (dialect == dialects.SOSL ? /(\\\}|[^}])+/ : /(\\\'|[^'])+/),
returning_clause: ($) =>
seq(ci("RETURNING"), commaJoined1($.sobject_return)),
sobject_return: ($) =>
seq(
$.identifier,
optional(
seq(
"(",
$.selected_fields,
optional($.using_clause),
optional($.where_clause),
optional($.order_by_clause),
optional($.limit_clause),
optional($.offset_clause),
")"
)
)
),
selected_fields: ($) => commaJoined1($._selectable_expression),
_selectable_expression: ($) =>
choice($._value_expression, $.alias_expression, $.fields_expression),
using_clause: ($) => seq(ci("USING"), ci("ListView"), "=", $.identifier),
subquery: ($) => seq("(", $.sosl_query_body, ")"),
with_division_expression: ($) =>
seq(
ci("DIVISION"),
"=",
choice($.bound_apex_expression, $.string_literal)
),
with_highlight: ($) => ci("HIGHLIGHT"),
with_metadata_expression: ($) =>
seq(ci("METADATA"), "=", $.string_literal),
with_network_expression: ($) => seq(ci("NETWORK"), $._comparison),
with_pricebook_expression: ($) =>
seq(ci("PricebookId"), "=", $.string_literal),
with_snippet_expression: ($) =>
seq(
ci("SNIPPET"),
optional(seq("(", ci("target_length"), "=", $.int, ")"))
),
with_spell_correction_expression: ($) =>
seq(ci("SPELL_CORRECTION"), "=", $.boolean),
sosl_with_type: ($) =>
choice(
$.with_data_cat_expression,
$.with_division_expression,
$.with_highlight,
$.with_metadata_expression,
$.with_network_expression,
$.with_pricebook_expression,
$.with_snippet_expression,
$.with_spell_correction_expression
),
sosl_with_clause: ($) =>
seq(ci("WITH"), alias($.sosl_with_type, $.with_type)),
...soqlGrammar.rules,
},
};
};

@ -0,0 +1,203 @@
<!--
Based on:
- https://github.com/tree-sitter/tree-sitter/blob/master/cli/src/web_ui.html
- https://github.com/stsewd/tree-sitter-rst/blob/master/docs/index.html
Assets from:
- https://github.com/tree-sitter/tree-sitter/blob/master/docs/assets/js/playground.js
- https://github.com/tree-sitter/tree-sitter.github.io/blob/master/tree-sitter.js
- https://github.com/tree-sitter/tree-sitter.github.io/blob/master/tree-sitter.wasm
-->
<head>
<meta charset="utf-8">
<title>Salesforce grammar for tree-sitter - tree-sitter-sfapex</title>
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/codemirror/5.45.0/codemirror.min.css">
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/clusterize.js/0.18.0/clusterize.min.css">
<link rel="icon" type="image/png" href="https://tree-sitter.github.io/tree-sitter/assets/images/favicon-32x32.png" sizes="32x32" />
<link rel="icon" type="image/png" href="https://tree-sitter.github.io/tree-sitter/assets/images/favicon-16x16.png" sizes="16x16" />
</head>
<body>
<div id="playground-container" style="visibility: hidden;">
<header>
<div class=header-item>
<bold>
<a href="https://github.com/aheber/tree-sitter-sfapex" target="_blank">
tree-sitter-sfapex
</a>
</bold>
</div>
<div class=header-item>
<label for="logging-checkbox">log</label>
<input id="logging-checkbox" type="checkbox"></input>
</div>
<div class=header-item>
<label for="query-checkbox">query</label>
<input id="query-checkbox" type="checkbox"></input>
</div>
<div class=header-item>
<label for="update-time">parse time: </label>
<span id="update-time"></span>
</div>
<select id="language-select">
<option value="apex">Apex</option>
<option value="soql">SOQL</option>
<option value="sosl">SOSL</option>
</select>
</header>
<main>
<div id="input-pane">
<div id="code-container">
<textarea id="code-input"></textarea>
</div>
<div id="query-container" style="visibility: hidden; position: absolute;">
<textarea id="query-input"></textarea>
</div>
</div>
<div id="output-container-scroll">
<pre id="output-container" class="highlight"></pre>
</div>
</main>
</div>
<script src="https://code.jquery.com/jquery-3.3.1.min.js" crossorigin="anonymous">
</script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/codemirror/5.45.0/codemirror.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/clusterize.js/0.18.0/clusterize.min.js"></script>
<script>LANGUAGE_BASE_URL = "js";</script>
<script src=js/tree-sitter.js></script>
<script src=js/playground.js></script>
<script>
(codeExample => {
const handle = setInterval(() => {
const $codeEditor = document.querySelector('.CodeMirror');
if ($codeEditor) {
$codeEditor.CodeMirror.setValue(codeExample);
clearInterval(handle);
}
}, 500);
})(`public class Me {
{
System.debug(a);
}
}
`);
</script>
<style>
body {
margin: 0;
padding: 0;
}
#playground-container {
width: 100%;
height: 100%;
display: flex;
flex-direction: column;
}
header {
box-sizing: border-box;
display: flex;
padding: 20px;
height: 60px;
border-bottom: 1px solid #aaa;
}
main {
flex: 1;
position: relative;
}
#input-pane {
position: absolute;
top: 0;
left: 0;
bottom: 0;
right: 50%;
display: flex;
flex-direction: column;
}
#code-container,
#query-container {
flex: 1;
position: relative;
overflow: hidden;
border-right: 1px solid #aaa;
border-bottom: 1px solid #aaa;
}
#output-container-scroll {
position: absolute;
top: 0;
left: 50%;
bottom: 0;
right: 0;
}
.header-item {
margin-right: 30px;
}
#playground-container .CodeMirror {
position: absolute;
top: 0;
bottom: 0;
left: 0;
right: 0;
height: 100%;
}
#output-container-scroll {
flex: 1;
padding: 0;
overflow: auto;
}
#output-container {
padding: 0 10px;
margin: 0;
}
#logging-checkbox {
vertical-align: middle;
}
.CodeMirror div.CodeMirror-cursor {
border-left: 3px solid red;
}
a {
text-decoration: none;
color: #040404;
padding: 2px;
}
a:hover {
text-decoration: underline;
}
a.highlighted {
background-color: #d9d9d9;
color: red;
border-radius: 3px;
text-decoration: underline;
}
.query-error {
text-decoration: underline red dashed;
}
</style>
</body>

@ -0,0 +1,478 @@
let tree;
(async () => {
const CAPTURE_REGEX = /@\s*([\w\._-]+)/g;
const COLORS_BY_INDEX = [
"blue",
"chocolate",
"darkblue",
"darkcyan",
"darkgreen",
"darkred",
"darkslategray",
"dimgray",
"green",
"indigo",
"navy",
"red",
"sienna",
];
const scriptURL = document.currentScript.getAttribute("src");
const codeInput = document.getElementById("code-input");
const languageSelect = document.getElementById("language-select");
const loggingCheckbox = document.getElementById("logging-checkbox");
const outputContainer = document.getElementById("output-container");
const outputContainerScroll = document.getElementById(
"output-container-scroll"
);
const playgroundContainer = document.getElementById("playground-container");
const queryCheckbox = document.getElementById("query-checkbox");
const queryContainer = document.getElementById("query-container");
const queryInput = document.getElementById("query-input");
const updateTimeSpan = document.getElementById("update-time");
const languagesByName = {};
loadState();
await TreeSitter.init();
const parser = new TreeSitter();
const codeEditor = CodeMirror.fromTextArea(codeInput, {
lineNumbers: true,
showCursorWhenSelecting: true,
});
const queryEditor = CodeMirror.fromTextArea(queryInput, {
lineNumbers: true,
showCursorWhenSelecting: true,
});
const cluster = new Clusterize({
rows: [],
noDataText: null,
contentElem: outputContainer,
scrollElem: outputContainerScroll,
});
const renderTreeOnCodeChange = debounce(renderTree, 50);
const saveStateOnChange = debounce(saveState, 2000);
const runTreeQueryOnChange = debounce(runTreeQuery, 50);
let languageName = languageSelect.value;
let treeRows = null;
let treeRowHighlightedIndex = -1;
let parseCount = 0;
let isRendering = 0;
let query;
codeEditor.on("changes", handleCodeChange);
codeEditor.on("viewportChange", runTreeQueryOnChange);
codeEditor.on("cursorActivity", debounce(handleCursorMovement, 150));
queryEditor.on("changes", debounce(handleQueryChange, 150));
loggingCheckbox.addEventListener("change", handleLoggingChange);
queryCheckbox.addEventListener("change", handleQueryEnableChange);
languageSelect.addEventListener("change", handleLanguageChange);
outputContainer.addEventListener("click", handleTreeClick);
handleQueryEnableChange();
await handleLanguageChange();
playgroundContainer.style.visibility = "visible";
async function handleLanguageChange() {
const newLanguageName = languageSelect.value;
if (!languagesByName[newLanguageName]) {
const url = `${LANGUAGE_BASE_URL}/tree-sitter-${newLanguageName}.wasm`;
languageSelect.disabled = true;
try {
languagesByName[newLanguageName] = await TreeSitter.Language.load(url);
} catch (e) {
console.error(e);
languageSelect.value = languageName;
return;
} finally {
languageSelect.disabled = false;
}
}
tree = null;
languageName = newLanguageName;
parser.setLanguage(languagesByName[newLanguageName]);
handleCodeChange();
handleQueryChange();
}
async function handleCodeChange(editor, changes) {
const newText = codeEditor.getValue() + "\n";
const edits = tree && changes && changes.map(treeEditForEditorChange);
const start = performance.now();
if (edits) {
for (const edit of edits) {
tree.edit(edit);
}
}
const newTree = parser.parse(newText, tree);
const duration = (performance.now() - start).toFixed(1);
updateTimeSpan.innerText = `${duration} ms`;
if (tree) tree.delete();
tree = newTree;
parseCount++;
renderTreeOnCodeChange();
runTreeQueryOnChange();
saveStateOnChange();
}
async function renderTree() {
isRendering++;
const cursor = tree.walk();
let currentRenderCount = parseCount;
let row = "";
let rows = [];
let finishedRow = false;
let visitedChildren = false;
let indentLevel = 0;
for (let i = 0; ; i++) {
if (i > 0 && i % 10000 === 0) {
await new Promise((r) => setTimeout(r, 0));
if (parseCount !== currentRenderCount) {
cursor.delete();
isRendering--;
return;
}
}
let displayName;
if (cursor.nodeIsMissing) {
displayName = `MISSING ${cursor.nodeType}`;
} else if (cursor.nodeIsNamed) {
displayName = cursor.nodeType;
}
if (visitedChildren) {
if (displayName) {
finishedRow = true;
}
if (cursor.gotoNextSibling()) {
visitedChildren = false;
} else if (cursor.gotoParent()) {
visitedChildren = true;
indentLevel--;
} else {
break;
}
} else {
if (displayName) {
if (finishedRow) {
row += "</div>";
rows.push(row);
finishedRow = false;
}
const start = cursor.startPosition;
const end = cursor.endPosition;
const id = cursor.nodeId;
let fieldName = cursor.currentFieldName();
if (fieldName) {
fieldName += ": ";
} else {
fieldName = "";
}
row = `<div>${" ".repeat(
indentLevel
)}${fieldName}<a class='plain' href="#" data-id=${id} data-range="${
start.row
},${start.column},${end.row},${end.column}">${displayName}</a> [${
start.row
}, ${start.column}] - [${end.row}, ${end.column}]`;
finishedRow = true;
}
if (cursor.gotoFirstChild()) {
visitedChildren = false;
indentLevel++;
} else {
visitedChildren = true;
}
}
}
if (finishedRow) {
row += "</div>";
rows.push(row);
}
cursor.delete();
cluster.update(rows);
treeRows = rows;
isRendering--;
handleCursorMovement();
}
function runTreeQuery(_, startRow, endRow) {
if (endRow == null) {
const viewport = codeEditor.getViewport();
startRow = viewport.from;
endRow = viewport.to;
}
codeEditor.operation(() => {
const marks = codeEditor.getAllMarks();
marks.forEach((m) => m.clear());
if (tree && query) {
const captures = query.captures(
tree.rootNode,
{ row: startRow, column: 0 },
{ row: endRow, column: 0 }
);
let lastNodeId;
for (const { name, node } of captures) {
if (node.id === lastNodeId) continue;
lastNodeId = node.id;
const { startPosition, endPosition } = node;
codeEditor.markText(
{ line: startPosition.row, ch: startPosition.column },
{ line: endPosition.row, ch: endPosition.column },
{
inclusiveLeft: true,
inclusiveRight: true,
css: `color: ${colorForCaptureName(name)}`,
}
);
}
}
});
}
function handleQueryChange() {
if (query) {
query.delete();
query.deleted = true;
query = null;
}
queryEditor.operation(() => {
queryEditor.getAllMarks().forEach((m) => m.clear());
if (!queryCheckbox.checked) return;
const queryText = queryEditor.getValue();
try {
query = parser.getLanguage().query(queryText);
let match;
let row = 0;
queryEditor.eachLine((line) => {
while ((match = CAPTURE_REGEX.exec(line.text))) {
queryEditor.markText(
{ line: row, ch: match.index },
{ line: row, ch: match.index + match[0].length },
{
inclusiveLeft: true,
inclusiveRight: true,
css: `color: ${colorForCaptureName(match[1])}`,
}
);
}
row++;
});
} catch (error) {
const startPosition = queryEditor.posFromIndex(error.index);
const endPosition = {
line: startPosition.line,
ch: startPosition.ch + (error.length || Infinity),
};
if (error.index === queryText.length) {
if (startPosition.ch > 0) {
startPosition.ch--;
} else if (startPosition.row > 0) {
startPosition.row--;
startPosition.column = Infinity;
}
}
queryEditor.markText(startPosition, endPosition, {
className: "query-error",
inclusiveLeft: true,
inclusiveRight: true,
attributes: { title: error.message },
});
}
});
runTreeQuery();
saveQueryState();
}
function handleCursorMovement() {
if (isRendering) return;
const selection = codeEditor.getDoc().listSelections()[0];
let start = { row: selection.anchor.line, column: selection.anchor.ch };
let end = { row: selection.head.line, column: selection.head.ch };
if (
start.row > end.row ||
(start.row === end.row && start.column > end.column)
) {
let swap = end;
end = start;
start = swap;
}
const node = tree.rootNode.namedDescendantForPosition(start, end);
if (treeRows) {
if (treeRowHighlightedIndex !== -1) {
const row = treeRows[treeRowHighlightedIndex];
if (row)
treeRows[treeRowHighlightedIndex] = row.replace(
"highlighted",
"plain"
);
}
treeRowHighlightedIndex = treeRows.findIndex((row) =>
row.includes(`data-id=${node.id}`)
);
if (treeRowHighlightedIndex !== -1) {
const row = treeRows[treeRowHighlightedIndex];
if (row)
treeRows[treeRowHighlightedIndex] = row.replace(
"plain",
"highlighted"
);
}
cluster.update(treeRows);
const lineHeight = cluster.options.item_height;
const scrollTop = outputContainerScroll.scrollTop;
const containerHeight = outputContainerScroll.clientHeight;
const offset = treeRowHighlightedIndex * lineHeight;
if (scrollTop > offset - 20) {
$(outputContainerScroll).animate({ scrollTop: offset - 20 }, 150);
} else if (scrollTop < offset + lineHeight + 40 - containerHeight) {
$(outputContainerScroll).animate(
{ scrollTop: offset - containerHeight + 40 },
150
);
}
}
}
function handleTreeClick(event) {
if (event.target.tagName === "A") {
event.preventDefault();
const [startRow, startColumn, endRow, endColumn] =
event.target.dataset.range.split(",").map((n) => parseInt(n));
codeEditor.focus();
codeEditor.setSelection(
{ line: startRow, ch: startColumn },
{ line: endRow, ch: endColumn }
);
}
}
function handleLoggingChange() {
if (loggingCheckbox.checked) {
parser.setLogger((message, lexing) => {
if (lexing) {
console.log(" ", message);
} else {
console.log(message);
}
});
} else {
parser.setLogger(null);
}
}
function handleQueryEnableChange() {
if (queryCheckbox.checked) {
queryContainer.style.visibility = "";
queryContainer.style.position = "";
} else {
queryContainer.style.visibility = "hidden";
queryContainer.style.position = "absolute";
}
handleQueryChange();
}
function treeEditForEditorChange(change) {
const oldLineCount = change.removed.length;
const newLineCount = change.text.length;
const lastLineLength = change.text[newLineCount - 1].length;
const startPosition = { row: change.from.line, column: change.from.ch };
const oldEndPosition = { row: change.to.line, column: change.to.ch };
const newEndPosition = {
row: startPosition.row + newLineCount - 1,
column:
newLineCount === 1
? startPosition.column + lastLineLength
: lastLineLength,
};
const startIndex = codeEditor.indexFromPos(change.from);
let newEndIndex = startIndex + newLineCount - 1;
let oldEndIndex = startIndex + oldLineCount - 1;
for (let i = 0; i < newLineCount; i++) newEndIndex += change.text[i].length;
for (let i = 0; i < oldLineCount; i++)
oldEndIndex += change.removed[i].length;
return {
startIndex,
oldEndIndex,
newEndIndex,
startPosition,
oldEndPosition,
newEndPosition,
};
}
function colorForCaptureName(capture) {
const id = query.captureNames.indexOf(capture);
return COLORS_BY_INDEX[id % COLORS_BY_INDEX.length];
}
function loadState() {
const language = localStorage.getItem("language");
const sourceCode = localStorage.getItem("sourceCode");
const query = localStorage.getItem("query");
const queryEnabled = localStorage.getItem("queryEnabled");
if (language != null && sourceCode != null && query != null) {
queryInput.value = query;
codeInput.value = sourceCode;
languageSelect.value = language;
queryCheckbox.checked = queryEnabled === "true";
}
}
function saveState() {
localStorage.setItem("language", languageSelect.value);
localStorage.setItem("sourceCode", codeEditor.getValue());
saveQueryState();
}
function saveQueryState() {
localStorage.setItem("queryEnabled", queryCheckbox.checked);
localStorage.setItem("query", queryEditor.getValue());
}
function debounce(func, wait, immediate) {
var timeout;
return function () {
var context = this,
args = arguments;
var later = function () {
timeout = null;
if (!immediate) func.apply(context, args);
};
var callNow = immediate && !timeout;
clearTimeout(timeout);
timeout = setTimeout(later, wait);
if (callNow) func.apply(context, args);
};
}
})();

File diff suppressed because one or more lines are too long

@ -0,0 +1,49 @@
# Use parsers and queries in nvim-treesitter plugin
The Apex, SOQL, and SOSL parsers in this repo are alredy part of [nvim-treesitter
repository](https://github.com/nvim-treesitter/nvim-treesitter).
Any parser new version in this repo is automatically syned in nvim-treesitter.
Note. Nvim-treesitter maintains its own version of `scm` [query files](https://github.com/nvim-treesitter/nvim-treesitter/tree/master/queries).
It means that the query files stored in this repo is not used by nvim-treesitter.
# How to install and use
Installing the nvim-treesitter plugin with whatever package manager you use.
I use `Lazy`, and you can find my Nvim dotfiles
[here](https://github.com/xixiaofinland/dotfiles/tree/main/.config/nvim).
Once the plugin is installed, the parsers and query files are part of the plugin in your
local installed version.
In your Nvim init configuraiton, you need to setup the filetypes so
nvim-treesitter automatically kicks-in when corresponding filetypes are opened.
```lua
vim.filetype = on
vim.filetype.add({
extension = {
cls = 'apex',
apex = 'apex',
trigger = 'apex',
soql = 'soql',
sosl = 'sosl',
}
})
```
Now when you open a `.cls` file, Nvim should use the `Apex` parser to parse the Apex language and
`highlights.scm` to highlight syntax.
# Troubleshoot
1. Are the parsers successfully installed?
Run `:TSInstallInfo` to see the parser installation information
2. No syntax highlight in Apex?
Sometimes the syntax higlight module is disabled, open an Apex file and run `:TSEnable highlight` to enable it.

File diff suppressed because it is too large Load Diff

@ -0,0 +1,95 @@
{
"name": "tree-sitter-sfapex",
"version": "0.0.9",
"description": "A tree-sitter implementation for Apex, SOQL, and SOSL",
"homepage": "https://github.com/aheber/tree-sitter-sfapex",
"bugs": {
"url": "https://github.com/aheber/tree-sitter-sfapex/issues"
},
"license": "MIT",
"author": {
"name": "Anthony Heber"
},
"repository": {
"type": "git",
"url": "https://github.com/aheber/tree-sitter-sfapex.git"
},
"dependencies": {
"@mapbox/node-pre-gyp": "^1.0.10",
"nan": "^2.16.0",
"node-pre-gyp-github": "^1.4.4"
},
"devDependencies": {
"tree-sitter-cli": "0.20.6"
},
"main": "bindings/node",
"scripts": {
"build": "npm run build-generate && npm run build-wasm",
"build-generate": "npm run build-apex && npm run build-soql && npm run build-sosl",
"build-apex": "cd apex && npx tree-sitter generate --no-bindings",
"build-soql": "cd soql && npx tree-sitter generate --no-bindings",
"build-sosl": "cd sosl && npx tree-sitter generate --no-bindings",
"build-wasm": "npm run build-apex-wasm && npm run build-soql-wasm && npm run build-sosl-wasm",
"build-apex-wasm": "cd apex && npx tree-sitter build-wasm && cp tree-sitter-apex.wasm ../docs/playground/js/",
"build-soql-wasm": "cd soql && npx tree-sitter build-wasm && cp tree-sitter-soql.wasm ../docs/playground/js/",
"build-sosl-wasm": "cd sosl && npx tree-sitter build-wasm && cp tree-sitter-sosl.wasm ../docs/playground/js/",
"test-load": "node -e \"require('./apex').then(apex => console.log(apex.name)), require('./soql').then(soql => console.log(soql.name)), require('./sosl').then(sosl => console.log(sosl.name))\"",
"test": "npm run test-apex && npm run test-soql && npm run test-sosl && npm run test-load",
"test-apex": "cd apex && npx tree-sitter test",
"test-soql": "cd soql && npx tree-sitter test",
"test-sosl": "cd sosl && npx tree-sitter test",
"install": "node-pre-gyp install --fallback-to-build"
},
"tree-sitter": [
{
"scope": "source.apex",
"path": "apex",
"file-types": [
"cls",
"trigger",
"apex"
],
"highlights": [
"soql/queries/highlights.scm",
"sosl/queries/highlights.scm",
"apex/queries/highlights.scm"
],
"tags": [
"apex/queries/tags.scm"
]
},
{
"scope": "source.soql",
"path": "soql",
"file-types": [
"soql"
],
"highlights": "soql/queries/highlights.scm"
},
{
"scope": "source.sosl",
"path": "sosl",
"file-types": [
"sosl"
],
"highlights": [
"soql/queries/highlights.scm",
"sosl/queries/highlights.scm"
]
}
],
"files": [
"*/queries/*",
"*/src/grammar.json",
"*/src/node-types.json",
"*/src/parser.c",
"*/src/tree_sitter/parser.h",
"binding.gyp"
],
"binary": {
"module_name": "tree_sitter_sfapex_binding",
"module_path": "./build/Release/",
"host": "https://github.com/aheber/tree-sitter-sfapex/releases/download/",
"remote_path": "{version}"
}
}

@ -0,0 +1,13 @@
import NodePreGypGithub from "node-pre-gyp-github";
try {
const opts = {
draft: false,
verbose: false,
target_commitish: "main",
};
const nodePreGypGithub = new NodePreGypGithub();
await nodePreGypGithub.publish(opts);
} catch (err) {
console.error(`An error occurred whilst publishing:`, err);
process.exit(1);
}

@ -0,0 +1,17 @@
const soqlGrammar = require("../common/soql-grammar.js")("soql");
module.exports = grammar({
name: "soql",
conflicts: soqlGrammar.conflicts,
// necessary to enable testing comments
extras: ($) => [$.formatting_comment, /\s/],
rules: {
source_file: ($) => seq(repeat($.header_comment), $._soql_query_expression),
header_comment: ($) => seq("//", /.*/),
formatting_comment: ($) => seq("///", /.*/),
...soqlGrammar.rules,
},
});

@ -0,0 +1,15 @@
{
"main": "../bindings/node/soql",
"tree-sitter": [
{
"scope": "source.soql",
"file-types": [
"soql"
],
"highlights": [
"queries/highlights-distinct.scm",
"queries/highlights.scm"
]
}
]
}

@ -0,0 +1,142 @@
; https://code.visualstudio.com/api/language-extensions/semantic-highlight-guide#semantic-token-classification
(field_identifier
(identifier) @property)
(field_identifier
(dotted_identifier
(identifier) @property))
(type_of_clause
(identifier) @property)
(when_expression
(identifier) @type)
(when_expression
(field_list
(identifier) @property))
(when_expression
(field_list
(dotted_identifier
(identifier) @property )))
(else_expression
(field_list
(identifier) @property ))
(else_expression
(field_list
(dotted_identifier
(identifier) @property )))
(alias_expression
(identifier) @label)
(storage_identifier) @type
(function_name) @function
(date_literal) @variable.readonly.defaultLibrary
[
","
"."
":"
"?"
"("
")"
] @punctuation
[
"AND"
"OR"
"NOT"
"="
"!="
"LIKE"
"NOT_IN"
"INCLUDES"
"EXCLUDES"
] @operator
(value_comparison_operator "<" @operator)
"<=" @operator
(value_comparison_operator ">" @operator)
">=" @operator
@operator
(set_comparison_operator "IN" @operator)
(int) @number
(decimal) @number
(currency_literal) @number
(string_literal) @string
(date) @variable.readonly
(date_time) @variable.readonly
[
"TRUE"
"FALSE"
(null_literal)
] @variable.readonly.defaultLibrary
[
"ABOVE"
"ABOVE_OR_BELOW"
"ALL_ROWS"
"ALL"
"AS"
"ASC"
"AT"
"BELOW"
"CUSTOM"
"DATA_CATEGORY"
"DESC"
"ELSE"
"END"
"FIELDS"
"FOR"
"FROM"
"GROUP_BY"
"HAVING"
"LIMIT"
"NULLS_FIRST"
"NULLS_LAST"
"OFFSET"
"ORDER_BY"
"REFERENCE"
"SELECT"
"STANDARD"
"THEN"
"TRACKING"
"TYPEOF"
"UPDATE"
"USING_SCOPE"
"VIEW"
"VIEWSTAT"
"WITH"
"WHERE"
"WHEN"
] @keyword
; Using Scope
[
"delegated"
"everything"
"mine"
"mine_and_my_groups"
"my_territory"
"my_team_territory"
"team"
] @enumMember
; With
[
"maxDescriptorPerRecord"
"RecordVisibilityContext"
"Security_Enforced"
"supportsDomains"
"supportsDelegates"
"System_Mode"
"User_Mode"
"UserId"
] @enumMember

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

@ -0,0 +1,224 @@
#ifndef TREE_SITTER_PARSER_H_
#define TREE_SITTER_PARSER_H_
#ifdef __cplusplus
extern "C" {
#endif
#include <stdbool.h>
#include <stdint.h>
#include <stdlib.h>
#define ts_builtin_sym_error ((TSSymbol)-1)
#define ts_builtin_sym_end 0
#define TREE_SITTER_SERIALIZATION_BUFFER_SIZE 1024
typedef uint16_t TSStateId;
#ifndef TREE_SITTER_API_H_
typedef uint16_t TSSymbol;
typedef uint16_t TSFieldId;
typedef struct TSLanguage TSLanguage;
#endif
typedef struct {
TSFieldId field_id;
uint8_t child_index;
bool inherited;
} TSFieldMapEntry;
typedef struct {
uint16_t index;
uint16_t length;
} TSFieldMapSlice;
typedef struct {
bool visible;
bool named;
bool supertype;
} TSSymbolMetadata;
typedef struct TSLexer TSLexer;
struct TSLexer {
int32_t lookahead;
TSSymbol result_symbol;
void (*advance)(TSLexer *, bool);
void (*mark_end)(TSLexer *);
uint32_t (*get_column)(TSLexer *);
bool (*is_at_included_range_start)(const TSLexer *);
bool (*eof)(const TSLexer *);
};
typedef enum {
TSParseActionTypeShift,
TSParseActionTypeReduce,
TSParseActionTypeAccept,
TSParseActionTypeRecover,
} TSParseActionType;
typedef union {
struct {
uint8_t type;
TSStateId state;
bool extra;
bool repetition;
} shift;
struct {
uint8_t type;
uint8_t child_count;
TSSymbol symbol;
int16_t dynamic_precedence;
uint16_t production_id;
} reduce;
uint8_t type;
} TSParseAction;
typedef struct {
uint16_t lex_state;
uint16_t external_lex_state;
} TSLexMode;
typedef union {
TSParseAction action;
struct {
uint8_t count;
bool reusable;
} entry;
} TSParseActionEntry;
struct TSLanguage {
uint32_t version;
uint32_t symbol_count;
uint32_t alias_count;
uint32_t token_count;
uint32_t external_token_count;
uint32_t state_count;
uint32_t large_state_count;
uint32_t production_id_count;
uint32_t field_count;
uint16_t max_alias_sequence_length;
const uint16_t *parse_table;
const uint16_t *small_parse_table;
const uint32_t *small_parse_table_map;
const TSParseActionEntry *parse_actions;
const char * const *symbol_names;
const char * const *field_names;
const TSFieldMapSlice *field_map_slices;
const TSFieldMapEntry *field_map_entries;
const TSSymbolMetadata *symbol_metadata;
const TSSymbol *public_symbol_map;
const uint16_t *alias_map;
const TSSymbol *alias_sequences;
const TSLexMode *lex_modes;
bool (*lex_fn)(TSLexer *, TSStateId);
bool (*keyword_lex_fn)(TSLexer *, TSStateId);
TSSymbol keyword_capture_token;
struct {
const bool *states;
const TSSymbol *symbol_map;
void *(*create)(void);
void (*destroy)(void *);
bool (*scan)(void *, TSLexer *, const bool *symbol_whitelist);
unsigned (*serialize)(void *, char *);
void (*deserialize)(void *, const char *, unsigned);
} external_scanner;
const TSStateId *primary_state_ids;
};
/*
* Lexer Macros
*/
#define START_LEXER() \
bool result = false; \
bool skip = false; \
bool eof = false; \
int32_t lookahead; \
goto start; \
next_state: \
lexer->advance(lexer, skip); \
start: \
skip = false; \
lookahead = lexer->lookahead;
#define ADVANCE(state_value) \
{ \
state = state_value; \
goto next_state; \
}
#define SKIP(state_value) \
{ \
skip = true; \
state = state_value; \
goto next_state; \
}
#define ACCEPT_TOKEN(symbol_value) \
result = true; \
lexer->result_symbol = symbol_value; \
lexer->mark_end(lexer);
#define END_STATE() return result;
/*
* Parse Table Macros
*/
#define SMALL_STATE(id) id - LARGE_STATE_COUNT
#define STATE(id) id
#define ACTIONS(id) id
#define SHIFT(state_value) \
{{ \
.shift = { \
.type = TSParseActionTypeShift, \
.state = state_value \
} \
}}
#define SHIFT_REPEAT(state_value) \
{{ \
.shift = { \
.type = TSParseActionTypeShift, \
.state = state_value, \
.repetition = true \
} \
}}
#define SHIFT_EXTRA() \
{{ \
.shift = { \
.type = TSParseActionTypeShift, \
.extra = true \
} \
}}
#define REDUCE(symbol_val, child_count_val, ...) \
{{ \
.reduce = { \
.type = TSParseActionTypeReduce, \
.symbol = symbol_val, \
.child_count = child_count_val, \
__VA_ARGS__ \
}, \
}}
#define RECOVER() \
{{ \
.type = TSParseActionTypeRecover \
}}
#define ACCEPT_INPUT() \
{{ \
.type = TSParseActionTypeAccept \
}}
#ifdef __cplusplus
}
#endif
#endif // TREE_SITTER_PARSER_H_

@ -0,0 +1,209 @@
================================================================================
Aggregate Count Id
================================================================================
SELECT COUNT(Id)
FROM Account
--------------------------------------------------------------------------------
(source_file
(soql_query_body
(select_clause
(function_expression
(function_name)
(field_identifier
(identifier))))
(from_clause
(storage_identifier
(identifier)))))
================================================================================
Aggregate Count Without Field
================================================================================
SELECT COUNT()
FROM Account
--------------------------------------------------------------------------------
(source_file
(soql_query_body
(select_clause
(count_expression
(function_name)))
(from_clause
(storage_identifier
(identifier)))))
================================================================================
Aggregate Count Multi
================================================================================
SELECT COUNT(Id), COUNT(CampaignId)
FROM Opportunity
--------------------------------------------------------------------------------
(source_file
(soql_query_body
(select_clause
(function_expression
(function_name)
(field_identifier
(identifier)))
(function_expression
(function_name)
(field_identifier
(identifier))))
(from_clause
(storage_identifier
(identifier)))))
================================================================================
Aggregate Count With Group
================================================================================
SELECT LeadSource, COUNT(Name)
FROM Lead
GROUP BY LeadSource
--------------------------------------------------------------------------------
(source_file
(soql_query_body
(select_clause
(field_identifier
(identifier))
(function_expression
(function_name)
(field_identifier
(identifier))))
(from_clause
(storage_identifier
(identifier)))
(group_by_clause
(field_identifier
(identifier)))))
================================================================================
Aggregate Avg
================================================================================
SELECT CampaignId, AVG(Amount)
FROM Opportunity
GROUP BY CampaignId
--------------------------------------------------------------------------------
(source_file
(soql_query_body
(select_clause
(field_identifier
(identifier))
(function_expression
(function_name)
(field_identifier
(identifier))))
(from_clause
(storage_identifier
(identifier)))
(group_by_clause
(field_identifier
(identifier)))))
================================================================================
Aggregate COUNT_DISTINCT
================================================================================
SELECT COUNT_DISTINCT(Company)
FROM Lead
--------------------------------------------------------------------------------
(source_file
(soql_query_body
(select_clause
(function_expression
(function_name)
(field_identifier
(identifier))))
(from_clause
(storage_identifier
(identifier)))))
================================================================================
Aggregate MIN
================================================================================
SELECT MIN(CreatedDate), FirstName, LastName
FROM Contact
GROUP BY FirstName, LastName
--------------------------------------------------------------------------------
(source_file
(soql_query_body
(select_clause
(function_expression
(function_name)
(field_identifier
(identifier)))
(field_identifier
(identifier))
(field_identifier
(identifier)))
(from_clause
(storage_identifier
(identifier)))
(group_by_clause
(field_identifier
(identifier))
(field_identifier
(identifier)))))
================================================================================
Aggregate MAX
================================================================================
SELECT Name, MAX(BudgetedCost)
FROM Campaign
GROUP BY Name
--------------------------------------------------------------------------------
(source_file
(soql_query_body
(select_clause
(field_identifier
(identifier))
(function_expression
(function_name)
(field_identifier
(identifier))))
(from_clause
(storage_identifier
(identifier)))
(group_by_clause
(field_identifier
(identifier)))))
================================================================================
Aggregate SUM
================================================================================
SELECT SUM(Amount)
FROM Opportunity
--------------------------------------------------------------------------------
(source_file
(soql_query_body
(select_clause
(function_expression
(function_name)
(field_identifier
(identifier))))
(from_clause
(storage_identifier
(identifier)))))

@ -0,0 +1,132 @@
================================================================================
Bound Equals (SOQL)
================================================================================
SELECT Id FROM Account WHERE Id = :id
--------------------------------------------------------------------------------
(source_file
(soql_query_body
(select_clause
(field_identifier
(identifier)))
(from_clause
(storage_identifier
(identifier))))
(ERROR
(field_identifier
(identifier))
(UNEXPECTED 'd')))
================================================================================
Bound List (SOQL)
================================================================================
SELECT Id FROM Account WHERE Id IN :idList
--------------------------------------------------------------------------------
(source_file
(soql_query_body
(select_clause
(field_identifier
(identifier)))
(from_clause
(storage_identifier
(identifier))))
(ERROR
(field_identifier
(identifier))
(UNEXPECTED 'd')))
================================================================================
Bound object function (SOQL)
================================================================================
SELECT Id FROM Account WHERE Id IN :object.function()
--------------------------------------------------------------------------------
(source_file
(soql_query_body
(select_clause
(field_identifier
(identifier)))
(from_clause
(storage_identifier
(identifier)))
(where_clause
(comparison_expression
(field_identifier
(identifier))
(set_comparison_operator)
(ERROR
(UNEXPECTED 'b')
(UNEXPECTED 'u'))
(boolean
(MISSING "TRUE"))))))
================================================================================
Bound object property (SOQL)
================================================================================
SELECT Id FROM Account WHERE Id IN :idList.blarg
--------------------------------------------------------------------------------
(source_file
(soql_query_body
(select_clause
(field_identifier
(identifier)))
(from_clause
(storage_identifier
(identifier))))
(ERROR
(field_identifier
(identifier))
(UNEXPECTED 'd')
(UNEXPECTED 'l')))
================================================================================
Bound safe navigation object property (SOQL)
================================================================================
SELECT Id FROM Account WHERE Id IN :idList?.blarg
--------------------------------------------------------------------------------
(source_file
(soql_query_body
(select_clause
(field_identifier
(identifier)))
(from_clause
(storage_identifier
(identifier))))
(ERROR
(field_identifier
(identifier))
(UNEXPECTED 'd')
(UNEXPECTED 'l')))
================================================================================
Apex Only ALL ROWS
================================================================================
SELECT COUNT() FROM Contact ALL ROWS
--------------------------------------------------------------------------------
(source_file
(soql_query_body
(select_clause
(count_expression
(function_name)))
(from_clause
(storage_alias
(storage_identifier
(identifier))
(identifier))))
(ERROR))

File diff suppressed because it is too large Load Diff

@ -0,0 +1,15 @@
================================================================================
SELECT Field matches Function Name
Function name matches field name
================================================================================
SELECT format
FROM Report
--------------------------------------------------------------------------------
(ERROR
(function_name)
(UNEXPECTED 'p')
(UNEXPECTED '\r'))

@ -0,0 +1,101 @@
================================================================================
FIELDS all
================================================================================
SELECT FIELDS(ALL) FROM Account
--------------------------------------------------------------------------------
(source_file
(soql_query_body
(select_clause
(fields_expression
(fields_type)))
(from_clause
(storage_identifier
(identifier)))))
================================================================================
FIELDS CUSTOM
================================================================================
SELECT FIELDS(CUSTOM) FROM Account
--------------------------------------------------------------------------------
(source_file
(soql_query_body
(select_clause
(fields_expression
(fields_type)))
(from_clause
(storage_identifier
(identifier)))))
================================================================================
FIELDS STANDARD
================================================================================
SELECT FIELDS(STANDARD) FROM Account
--------------------------------------------------------------------------------
(source_file
(soql_query_body
(select_clause
(fields_expression
(fields_type)))
(from_clause
(storage_identifier
(identifier)))))
================================================================================
FIELDS mix with literal fields
================================================================================
SELECT Name, Id, FIELDS(CUSTOM) FROM Account
--------------------------------------------------------------------------------
(source_file
(soql_query_body
(select_clause
(field_identifier
(identifier))
(field_identifier
(identifier))
(fields_expression
(fields_type)))
(from_clause
(storage_identifier
(identifier)))))
================================================================================
FIELDS in sub-query
================================================================================
SELECT
Account.Name,
(SELECT FIELDS(ALL) FROM Contacts)
FROM Account
--------------------------------------------------------------------------------
(source_file
(soql_query_body
(select_clause
(field_identifier
(dotted_identifier
(identifier)
(identifier)))
(subquery
(soql_query_body
(select_clause
(fields_expression
(fields_type)))
(from_clause
(storage_identifier
(identifier))))))
(from_clause
(storage_identifier
(identifier)))))

@ -0,0 +1,88 @@
================================================================================
For View
================================================================================
SELECT Name, ID FROM Contact LIMIT 1 FOR VIEW
--------------------------------------------------------------------------------
(source_file
(soql_query_body
(select_clause
(field_identifier
(identifier))
(field_identifier
(identifier)))
(from_clause
(storage_identifier
(identifier)))
(limit_clause
(int))
(for_clause
(for_type))))
================================================================================
For Reference
================================================================================
SELECT Name, ID FROM Contact LIMIT 1 FOR REFERENCE
--------------------------------------------------------------------------------
(source_file
(soql_query_body
(select_clause
(field_identifier
(identifier))
(field_identifier
(identifier)))
(from_clause
(storage_identifier
(identifier)))
(limit_clause
(int))
(for_clause
(for_type))))
================================================================================
For Update
================================================================================
SELECT Id FROM Account LIMIT 2 FOR UPDATE
--------------------------------------------------------------------------------
(source_file
(soql_query_body
(select_clause
(field_identifier
(identifier)))
(from_clause
(storage_identifier
(identifier)))
(limit_clause
(int))
(for_clause
(for_type))))
================================================================================
For View, Reference
================================================================================
SELECT Id FROM Account LIMIT 2 FOR UPDATE, REFERENCE
--------------------------------------------------------------------------------
(source_file
(soql_query_body
(select_clause
(field_identifier
(identifier)))
(from_clause
(storage_identifier
(identifier)))
(limit_clause
(int))
(for_clause
(for_type)
(for_type))))

@ -0,0 +1,90 @@
================================================================================
Format
================================================================================
SELECT FORMAT(amount) Amt,
format(lastModifiedDate) editDate
FROM Opportunity
--------------------------------------------------------------------------------
(source_file
(soql_query_body
(select_clause
(alias_expression
(function_expression
(function_name)
(field_identifier
(identifier)))
(identifier))
(alias_expression
(function_expression
(function_name)
(field_identifier
(identifier)))
(identifier)))
(from_clause
(storage_identifier
(identifier)))))
================================================================================
Format with Nested Convert Currency
================================================================================
SELECT amount, FORMAT(amount) Amt, convertCurrency(amount) editDate,
FORMAT(convertCurrency(amount)) convertedCurrency
FROM Opportunity
--------------------------------------------------------------------------------
(source_file
(soql_query_body
(select_clause
(field_identifier
(identifier))
(alias_expression
(function_expression
(function_name)
(field_identifier
(identifier)))
(identifier))
(alias_expression
(function_expression
(function_name)
(field_identifier
(identifier)))
(identifier))
(alias_expression
(function_expression
(function_name)
(function_expression
(function_name)
(field_identifier
(identifier))))
(identifier)))
(from_clause
(storage_identifier
(identifier)))))
================================================================================
Format Nested Aggregate
================================================================================
SELECT FORMAT(MIN(closedate)) Amt FROM opportunity
--------------------------------------------------------------------------------
(source_file
(soql_query_body
(select_clause
(alias_expression
(function_expression
(function_name)
(function_expression
(function_name)
(field_identifier
(identifier))))
(identifier)))
(from_clause
(storage_identifier
(identifier)))))

@ -0,0 +1,467 @@
================================================================================
GROUP BY
================================================================================
SELECT Name, Max(CreatedDate)
FROM Account
GROUP BY Name
--------------------------------------------------------------------------------
(source_file
(soql_query_body
(select_clause
(field_identifier
(identifier))
(function_expression
(function_name)
(field_identifier
(identifier))))
(from_clause
(storage_identifier
(identifier)))
(group_by_clause
(field_identifier
(identifier)))))
================================================================================
GROUP BY Multi
================================================================================
SELECT Name, CreatedById, Max(CreatedDate)
FROM Account
GROUP BY Name, CreatedById
--------------------------------------------------------------------------------
(source_file
(soql_query_body
(select_clause
(field_identifier
(identifier))
(field_identifier
(identifier))
(function_expression
(function_name)
(field_identifier
(identifier))))
(from_clause
(storage_identifier
(identifier)))
(group_by_clause
(field_identifier
(identifier))
(field_identifier
(identifier)))))
================================================================================
GROUP BY Aggregate Alias
================================================================================
SELECT Name n, MAX(Amount) max
FROM Opportunity
GROUP BY Name
--------------------------------------------------------------------------------
(source_file
(soql_query_body
(select_clause
(alias_expression
(field_identifier
(identifier))
(identifier))
(alias_expression
(function_expression
(function_name)
(field_identifier
(identifier)))
(identifier)))
(from_clause
(storage_identifier
(identifier)))
(group_by_clause
(field_identifier
(identifier)))))
================================================================================
GROUP BY Aggregate Alias multi
================================================================================
SELECT Name, MAX(Amount), MIN(Amount) min, SUM(Amount)
FROM Opportunity
GROUP BY Name
--------------------------------------------------------------------------------
(source_file
(soql_query_body
(select_clause
(field_identifier
(identifier))
(function_expression
(function_name)
(field_identifier
(identifier)))
(alias_expression
(function_expression
(function_name)
(field_identifier
(identifier)))
(identifier))
(function_expression
(function_name)
(field_identifier
(identifier))))
(from_clause
(storage_identifier
(identifier)))
(group_by_clause
(field_identifier
(identifier)))))
================================================================================
GROUP BY Rollup
================================================================================
SELECT LeadSource, COUNT(Name) cnt
FROM Lead
GROUP BY ROLLUP(LeadSource)
--------------------------------------------------------------------------------
(source_file
(soql_query_body
(select_clause
(field_identifier
(identifier))
(alias_expression
(function_expression
(function_name)
(field_identifier
(identifier)))
(identifier)))
(from_clause
(storage_identifier
(identifier)))
(group_by_clause
(function_name)
(field_identifier
(identifier)))))
================================================================================
GROUP BY Rollup Multi
================================================================================
SELECT LeadSource, COUNT(Name) cnt
FROM Lead
GROUP BY ROLLUP(LeadSource)
--------------------------------------------------------------------------------
(source_file
(soql_query_body
(select_clause
(field_identifier
(identifier))
(alias_expression
(function_expression
(function_name)
(field_identifier
(identifier)))
(identifier)))
(from_clause
(storage_identifier
(identifier)))
(group_by_clause
(function_name)
(field_identifier
(identifier)))))
================================================================================
GROUP BY Rollup with Subtotals
================================================================================
SELECT LeadSource, Rating,
GROUPING(LeadSource) grpLS, GROUPING(Rating) grpRating,
COUNT(Name) cnt
FROM Lead
GROUP BY ROLLUP(LeadSource, Rating)
--------------------------------------------------------------------------------
(source_file
(soql_query_body
(select_clause
(field_identifier
(identifier))
(field_identifier
(identifier))
(alias_expression
(function_expression
(function_name)
(field_identifier
(identifier)))
(identifier))
(alias_expression
(function_expression
(function_name)
(field_identifier
(identifier)))
(identifier))
(alias_expression
(function_expression
(function_name)
(field_identifier
(identifier)))
(identifier)))
(from_clause
(storage_identifier
(identifier)))
(group_by_clause
(function_name)
(field_identifier
(identifier))
(field_identifier
(identifier)))))
================================================================================
GROUP BY Cube
================================================================================
SELECT Type, BillingCountry,
GROUPING(Type) grpType, GROUPING(BillingCountry) grpCty,
COUNT(id) accts
FROM Account
GROUP BY CUBE(Type, BillingCountry)
ORDER BY GROUPING(Type), GROUPING(BillingCountry)
--------------------------------------------------------------------------------
(source_file
(soql_query_body
(select_clause
(field_identifier
(identifier))
(field_identifier
(identifier))
(alias_expression
(function_expression
(function_name)
(field_identifier
(identifier)))
(identifier))
(alias_expression
(function_expression
(function_name)
(field_identifier
(identifier)))
(identifier))
(alias_expression
(function_expression
(function_name)
(field_identifier
(identifier)))
(identifier)))
(from_clause
(storage_identifier
(identifier)))
(group_by_clause
(function_name)
(field_identifier
(identifier))
(field_identifier
(identifier)))
(order_by_clause
(order_expression
(function_expression
(function_name)
(field_identifier
(identifier))))
(order_expression
(function_expression
(function_name)
(field_identifier
(identifier)))))))
================================================================================
GROUP BY Cube w/ Order Props
================================================================================
SELECT Type, BillingCountry,
GROUPING(Type) grpType, GROUPING(BillingCountry) grpCty,
COUNT(id) accts
FROM Account
GROUP BY CUBE(Type, BillingCountry)
ORDER BY GROUPING(Type) DESC, GROUPING(BillingCountry) ASC NULLS LAST
--------------------------------------------------------------------------------
(source_file
(soql_query_body
(select_clause
(field_identifier
(identifier))
(field_identifier
(identifier))
(alias_expression
(function_expression
(function_name)
(field_identifier
(identifier)))
(identifier))
(alias_expression
(function_expression
(function_name)
(field_identifier
(identifier)))
(identifier))
(alias_expression
(function_expression
(function_name)
(field_identifier
(identifier)))
(identifier)))
(from_clause
(storage_identifier
(identifier)))
(group_by_clause
(function_name)
(field_identifier
(identifier))
(field_identifier
(identifier)))
(order_by_clause
(order_expression
(function_expression
(function_name)
(field_identifier
(identifier)))
(order_direction))
(order_expression
(function_expression
(function_name)
(field_identifier
(identifier)))
(order_direction)
(order_null_direciton)))))
================================================================================
GROUP BY Having
================================================================================
SELECT LeadSource, COUNT(Name)
FROM Lead
GROUP BY LeadSource
HAVING COUNT(Name) > 100 and MAX(LeadSource) > 'Phone'
--------------------------------------------------------------------------------
(source_file
(soql_query_body
(select_clause
(field_identifier
(identifier))
(function_expression
(function_name)
(field_identifier
(identifier))))
(from_clause
(storage_identifier
(identifier)))
(group_by_clause
(field_identifier
(identifier))
(having_clause
(having_and_expression
(having_comparison_expression
(function_expression
(function_name)
(field_identifier
(identifier)))
(value_comparison_operator)
(int))
(having_comparison_expression
(function_expression
(function_name)
(field_identifier
(identifier)))
(value_comparison_operator)
(string_literal)))))))
================================================================================
GROUP BY Having complex logic
================================================================================
SELECT LeadSource, COUNT(Name)
FROM Lead
GROUP BY LeadSource
HAVING COUNT(Name) > 100 and (MIN(LeadSource) > 'Phone' OR MAX(LeadSource) < 'Phone')
--------------------------------------------------------------------------------
(source_file
(soql_query_body
(select_clause
(field_identifier
(identifier))
(function_expression
(function_name)
(field_identifier
(identifier))))
(from_clause
(storage_identifier
(identifier)))
(group_by_clause
(field_identifier
(identifier))
(having_clause
(having_and_expression
(having_comparison_expression
(function_expression
(function_name)
(field_identifier
(identifier)))
(value_comparison_operator)
(int))
(having_or_expression
(having_comparison_expression
(function_expression
(function_name)
(field_identifier
(identifier)))
(value_comparison_operator)
(string_literal))
(having_comparison_expression
(function_expression
(function_name)
(field_identifier
(identifier)))
(value_comparison_operator)
(string_literal))))))))
================================================================================
GROUP BY Function
================================================================================
SELECT Id
FROM Account
GROUP BY DAY_ONLY(CreatedDate), Id
--------------------------------------------------------------------------------
(source_file
(soql_query_body
(select_clause
(field_identifier
(identifier)))
(from_clause
(storage_identifier
(identifier)))
(group_by_clause
(function_expression
(function_name)
(field_identifier
(identifier)))
(field_identifier
(identifier)))))

Some files were not shown because too many files have changed in this diff Show More