Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
27 changes: 22 additions & 5 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,24 +5,41 @@ All notable changes to this project will be documented in this file.
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).

## [0.2.2] - 2026-02-14
## [0.2.2] - 2026-02-15

### Added

- Dedicated test environment using Github Actions

- Description on how to build the LSP framework to correctly compile the Server using the scons
- Detailed documentation for some builtin functions (not all yet)
- Missing group_uniforms support (including nested structures)

- Sematics
- Missing group_uniforms support (including nested structures)
- Detection for recursion calls and appropiate errors

### Changed

- In code documentation
- Symbol Table
- Symbol lookups have a scope depth paremeter now
- Added functionality to lookup all symbols across all scopes
- Symbols now seperate symbol type and mutability. This resolves a lot of problems with tracking builtins and godots "in" or "out" parameters

### Fixed

- Included sky shaders in shader scope
- Sky shaders now correctly have acces to their builtin variables
- Shader type behaviour:
- Included sky shaders in shader scope
- Sky shaders now correctly have acces to their builtin variables
- Default behaviour of shader files that are missing the shader_type declaration no longer is spatial shader

- Parser
- Const declarations in parseStatement are correctly detected now

- Semantic Analyzer
- Const evaluation of builtins and user declared symbols
- Binary operations with bools now correctly report an error
- Scalar constructor checks are not skippe anymoren through logic error
- Segfaulting on RootSymbol acces for swizzles and array due to unchecked nullptr return

## [0.2.1] - 2025-12-01

Expand Down
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -74,7 +74,7 @@ This project uses **SCons** as its build system.

This project expects the **LSP Framework** to be located at `extern/lsp-framework`. You must compile the framework for your target platform and ensure the build artifacts are located in the specific directories expected by the `SConstruct` script:

* **Linux**: `extern/lsp-framework/build`
* **Linux**: `extern/lsp-framework/build_linux`
* **Windows**: `extern/lsp-framework/build_windows`
* **macOS**: `extern/lsp-framework/build_macos`

Expand Down
104 changes: 55 additions & 49 deletions src/gdshader/builtins.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,8 @@ namespace gdshader_lsp {
// ENUMS
// -------------------------------------------------------------------------

enum class ShaderType {
enum class ShaderType
{
Spatial,
CanvasItem,
Particles,
Expand All @@ -21,7 +22,8 @@ enum class ShaderType {
Unknown
};

enum class ShaderStage {
enum class ShaderStage
{
Global,
Vertex,
Fragment,
Expand All @@ -38,8 +40,9 @@ enum class ShaderStage {

struct BuiltinVariable {
std::string name;
std::string type; // e.g., "vec3", "float"
std::string type;
std::string doc;
std::string qualifier = "in";
};

struct BuiltinFunction {
Expand All @@ -62,6 +65,7 @@ using BuiltinFuncList = std::vector<BuiltinFunction>;
static const BuiltinList SPATIAL_VERTEX = {

// Global

{"TIME", "float", "Global time in seconds."},
{"PI", "float", "PI constant (3.141592)."},
{"TAU", "float", "TAU constant (6.283185)."},
Expand Down Expand Up @@ -90,33 +94,35 @@ static const BuiltinList SPATIAL_VERTEX = {

{"VERTEX", "vec3", "Vertex position in model space (or world if using world_vertex_coords)."},
{"VERTEX_ID", "int", "Index of the current vertex."},
{"NORMAL", "vec3", "Normal in model space."},
{"TANGENT", "vec3", "Tangent in model space."},
{"BINORMAL", "vec3", "Binormal in model space."},
{"POSITION", "vec4", "Override final vertex position in clip space."},
{"UV", "vec2", "UV main channel."},
{"UV2", "vec2", "UV secondary channel."},
{"COLOR", "vec4", "Vertex color."},
{"NORMAL", "vec3", "Normal in model space.", "inout"},
{"TANGENT", "vec3", "Tangent in model space.", "inout"},
{"BINORMAL", "vec3", "Binormal in model space.", "inout"},
{"POSITION", "vec4", "Override final vertex position in clip space.", "out"},
{"UV", "vec2", "UV main channel.", "inout"},
{"UV2", "vec2", "UV secondary channel.", "inout"},
{"COLOR", "vec4", "Vertex color.", "inout"},
{"ROUGHNESS", "float", "Roughness for vertex lighting."},
{"POINT_SIZE", "float", "Point size for point rendering."},
{"POINT_SIZE", "float", "Point size for point rendering.", "inout"},

{"MODELVIEW_MATRIX", "mat4", "Model space to view space transform."},
{"MODELVIEW_NORMAL_MATRIX", "mat3", "Model space to view space normal transform."},
{"MODELVIEW_MATRIX", "mat4", "Model space to view space transform.", "inout"},
{"MODELVIEW_NORMAL_MATRIX", "mat3", "Model space to view space normal transform.", "inout"},
{"MODEL_MATRIX", "mat4", "Model space to world space transform."},
{"MODEL_NORMAL_MATRIX", "mat3", "Model space to world space normal transform."},
{"PROJECTION_MATRIX", "mat4", "View space to clip space transform."},
{"PROJECTION_MATRIX", "mat4", "View space to clip space transform.", "inout"},

{"BONE_INDICES", "uvec4", "Bone indices."},
{"BONE_WEIGHTS", "vec4", "Bone weights."},
{"CUSTOM0", "vec4", "Custom value 0 (UV3/UV4)."},
{"CUSTOM1", "vec4", "Custom value 1 (UV5/UV6)."},
{"CUSTOM2", "vec4", "Custom value 2 (UV7/UV8)."},
{"CUSTOM3", "vec4", "Custom value 3."}
{"CUSTOM3", "vec4", "Custom value 3."},
{"Z_CLIP_SCALE", "float", "If written to, scales the vertex towards the camera to avoid clipping into things like walls. Lighting and shadows will continue to work correctly when this is written to, but screen-space effects like SSAO and SSR may break with lower scales. Try to keep this value as close to 1.0 as possible.", "out"}
};

static const BuiltinList SPATIAL_FRAGMENT = {

// Global

{"TIME", "float", "Global time in seconds."},
{"PI", "float", "PI constant (3.141592)."},
{"TAU", "float", "TAU constant (6.283185)."},
Expand Down Expand Up @@ -148,46 +154,46 @@ static const BuiltinList SPATIAL_FRAGMENT = {
{"CAMERA_VISIBLE_LAYERS", "uint", "Camera cull layers."},

{"VERTEX", "vec3", "Fragment position in view space."},
{"LIGHT_VERTEX", "vec3", "Writable VERTEX for lighting calculations (does not move pixel)."},
{"LIGHT_VERTEX", "vec3", "Writable VERTEX for lighting calculations (does not move pixel).", "inout"},
{"VIEW_INDEX", "int", "View index."},
{"VIEW_MONO_LEFT", "int", "Constant 0."},
{"VIEW_RIGHT", "int", "Constant 1."},
{"EYE_OFFSET", "vec3", "Eye offset."},
{"SCREEN_UV", "vec2", "Screen UV coordinates."},

{"DEPTH", "float", "Custom depth value."},
{"NORMAL", "vec3", "Normal in view space."},
{"TANGENT", "vec3", "Tangent in view space."},
{"BINORMAL", "vec3", "Binormal in view space."},
{"NORMAL_MAP", "vec3", "Normal map value."},
{"NORMAL_MAP_DEPTH", "float", "Normal map depth (default 1.0)."},
{"ALBEDO", "vec3", "Base color."},
{"ALPHA", "float", "Opacity."},
{"ALPHA_SCISSOR_THRESHOLD", "float", "Discard threshold."},
{"ALPHA_HASH_SCALE", "float", "Alpha hash scale."},
{"ALPHA_ANTIALIASING_EDGE", "float", "Alpha AA edge."},
{"ALPHA_TEXTURE_COORDINATE", "vec2", "Texture coord for Alpha AA."},
{"PREMUL_ALPHA_FACTOR", "float", "Premultiplied alpha factor."},
{"METALLIC", "float", "Metallic (0.0 - 1.0)."},
{"SPECULAR", "float", "Specular (0.0 - 1.0)."},
{"ROUGHNESS", "float", "Roughness (0.0 - 1.0)."},
{"RIM", "float", "Rim lighting."},
{"RIM_TINT", "float", "Rim tint."},
{"CLEARCOAT", "float", "Clearcoat intensity."},
{"CLEARCOAT_GLOSS", "float", "Clearcoat gloss."},
{"ANISOTROPY", "float", "Anisotropy strength."},
{"ANISOTROPY_FLOW", "vec2", "Anisotropy direction."},
{"SSS_STRENGTH", "float", "Subsurface scattering strength."},
{"SSS_TRANSMITTANCE_COLOR", "vec4", "SSS Transmittance color."},
{"SSS_TRANSMITTANCE_DEPTH", "float", "SSS Transmittance depth."},
{"SSS_TRANSMITTANCE_BOOST", "float", "SSS Transmittance boost."},
{"BACKLIGHT", "vec3", "Backlight color."},
{"AO", "float", "Ambient occlusion."},
{"AO_LIGHT_AFFECT", "float", "AO light affect."},
{"EMISSION", "vec3", "Emission color."},
{"FOG", "vec4", "Fog blend."},
{"RADIANCE", "vec4", "Radiance blend."},
{"IRRADIANCE", "vec4", "Irradiance blend."}
{"DEPTH", "float", "Custom depth value.", "out"},
{"NORMAL", "vec3", "Normal in view space.", "inout"},
{"TANGENT", "vec3", "Tangent in view space.", "inout"},
{"BINORMAL", "vec3", "Binormal in view space.", "inout"},
{"NORMAL_MAP", "vec3", "Normal map value.", "out"},
{"NORMAL_MAP_DEPTH", "float", "Normal map depth (default 1.0).", "out"},
{"ALBEDO", "vec3", "Base color.", "out"},
{"ALPHA", "float", "Opacity.", "out"},
{"ALPHA_SCISSOR_THRESHOLD", "float", "Discard threshold.", "out"},
{"ALPHA_HASH_SCALE", "float", "Alpha hash scale.", "out"},
{"ALPHA_ANTIALIASING_EDGE", "float", "Alpha AA edge.", "out"},
{"ALPHA_TEXTURE_COORDINATE", "vec2", "Texture coord for Alpha AA.", "out"},
{"PREMUL_ALPHA_FACTOR", "float", "Premultiplied alpha factor.", "out"},
{"METALLIC", "float", "Metallic (0.0 - 1.0).", "out"},
{"SPECULAR", "float", "Specular (0.0 - 1.0).", "out"},
{"ROUGHNESS", "float", "Roughness (0.0 - 1.0).", "out"},
{"RIM", "float", "Rim lighting.", "out"},
{"RIM_TINT", "float", "Rim tint.", "out"},
{"CLEARCOAT", "float", "Clearcoat intensity.", "out"},
{"CLEARCOAT_GLOSS", "float", "Clearcoat gloss.", "out"},
{"ANISOTROPY", "float", "Anisotropy strength.", "out"},
{"ANISOTROPY_FLOW", "vec2", "Anisotropy direction.", "out"},
{"SSS_STRENGTH", "float", "Subsurface scattering strength.", "out"},
{"SSS_TRANSMITTANCE_COLOR", "vec4", "SSS Transmittance color.", "out"},
{"SSS_TRANSMITTANCE_DEPTH", "float", "SSS Transmittance depth.", "out"},
{"SSS_TRANSMITTANCE_BOOST", "float", "SSS Transmittance boost.", "out"},
{"BACKLIGHT", "vec3", "Backlight color.", "inout"},
{"AO", "float", "Ambient occlusion.", "out"},
{"AO_LIGHT_AFFECT", "float", "AO light affect.", "out"},
{"EMISSION", "vec3", "Emission color.", "out"},
{"FOG", "vec4", "Fog blend.", "out"},
{"RADIANCE", "vec4", "Radiance blend.", "out"},
{"IRRADIANCE", "vec4", "Irradiance blend.", "out"}
};

static const BuiltinList SPATIAL_LIGHT = {
Expand Down
1 change: 0 additions & 1 deletion src/gdshader/lexer/lexer_types.h
Original file line number Diff line number Diff line change
Expand Up @@ -256,7 +256,6 @@ inline std::string tokenTypeToString(TokenType t) {
return "UNKNOWN_TOKEN";
}


struct Token {
TokenType type;
std::string value;
Expand Down
18 changes: 11 additions & 7 deletions src/gdshader/parser/parser.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -725,9 +725,8 @@ std::unique_ptr<StatementNode> Parser::parseStatement()
if (check(TokenType::TOKEN_LBRACE)) {
return parseBlock();
}

// Variable Declaration? "int x = 5;"
if (isTypeStart()) {

if (check(TokenType::KEYWORD_CONST) || isTypeStart()) {
return parseVarDecl();
}

Expand All @@ -738,8 +737,12 @@ std::unique_ptr<StatementNode> Parser::parseVarDecl()
{
Token start = current_token;
auto node = std::make_unique<VariableDeclNode>();
node->type = parseType();

if (match(TokenType::KEYWORD_CONST)) {
node->isConst = true;
}

node->type = parseType();
if (check(TokenType::TOKEN_IDENTIFIER)) {
node->name = current_token.value;

Expand Down Expand Up @@ -1272,7 +1275,7 @@ std::unique_ptr<TypeNode> gdshader_lsp::Parser::parseType()
// 1. Optional Precision (highp/lowp) - mostly ignored in Godot but valid syntax
if (match(TokenType::KEYWORD_HIGH_PRECISION)) {
node->precision = previous_token.value;
}
}

// 2. Base Type Name
if (isTypeStart()) {
Expand Down Expand Up @@ -1332,6 +1335,8 @@ void gdshader_lsp::Parser::setRange(ASTNode *node, const Token &start, const Tok
}

bool Parser::isTypeStart() {

SPDLOG_TRACE("Checking is type start for token {}", current_token.toString());
switch (current_token.type) {

case TokenType::KEYWORD_VOID:
Expand Down Expand Up @@ -1365,8 +1370,7 @@ bool Parser::isTypeStart() {

case TokenType::TOKEN_IDENTIFIER: {

Token next = lexer.peekToken(0); // Peek next (offset 0 usually means next in queue?)

Token next = lexer.peekToken(0);
if (next.type == TokenType::TOKEN_IDENTIFIER) {
return true;
}
Expand Down
Loading