{ "$schema": "https://raw.githubusercontent.com/martinring/tmlanguage/master/tmlanguage.json", "name": "Ludic", "scopeName": "source.ludic", "fileTypes": ["ludic"], "comment": "Static grammar for Ludic. It is the fallback: when ludic-lsp is running, its semantic tokens refine everything here with real name resolution. Generated shapes are kept in sync with tools/ludic-tools/ludic_syntax.h.", "patterns": [ { "include": "#comment" }, { "include": "#declaration" }, { "include": "#query" }, { "include": "#string" }, { "include": "#number" }, { "include": "#annotation" }, { "include": "#keyword" }, { "include": "#widget" }, { "include": "#builtin" }, { "include": "#member" }, { "include": "#call" }, { "include": "#typename" }, { "include": "#operator" } ], "repository": { "comment": { "match": "#.*$", "name": "comment.line.number-sign.ludic" }, "string": { "patterns": [ { "name": "string.quoted.double.ludic", "begin": "\"", "end": "\"", "beginCaptures": { "0": { "name": "punctuation.definition.string.begin.ludic" } }, "endCaptures": { "0": { "name": "punctuation.definition.string.end.ludic" } }, "patterns": [{ "name": "constant.character.escape.ludic", "match": "\\\\." }] }, { "name": "string.quoted.single.ludic", "match": "'(\\\\.|[^'\\\\])'" }, { "name": "string.interpolated.ludic", "begin": "`", "end": "`", "beginCaptures": { "0": { "name": "punctuation.definition.string.begin.ludic" } }, "endCaptures": { "0": { "name": "punctuation.definition.string.end.ludic" } }, "patterns": [ { "name": "meta.embedded.ludic", "begin": "\\{", "end": "\\}", "patterns": [{ "include": "$self" }] }, { "name": "constant.character.escape.ludic", "match": "\\\\." } ] } ] }, "number": { "patterns": [ { "name": "constant.numeric.hex.ludic", "match": "\\b0[xX][0-9a-fA-F]+\\b" }, { "name": "constant.numeric.fixed.ludic", "match": "\\b[0-9]+\\.[0-9]+\\b" }, { "name": "constant.numeric.integer.ludic", "match": "\\b[0-9]+\\b" } ] }, "annotation": { "name": "entity.name.function.decorator.ludic", "match": "@[A-Za-z_][A-Za-z0-9_]*" }, "declaration": { "patterns": [ { "match": "\\b(program)\\s+([A-Za-z_][A-Za-z0-9_]*)", "captures": { "1": { "name": "keyword.control.unit.ludic" }, "2": { "name": "entity.name.type.unit.ludic" } } }, { "match": "\\b(property)\\s+([A-Za-z_][A-Za-z0-9_]*)", "captures": { "1": { "name": "storage.type.component.ludic" }, "2": { "name": "entity.name.type.component.ludic" } } }, { "match": "\\b(model)\\s+([A-Za-z_][A-Za-z0-9_]*)", "captures": { "1": { "name": "storage.type.archetype.ludic" }, "2": { "name": "entity.name.type.archetype.ludic" } } }, { "match": "\\b(ui)\\s+([A-Za-z_][A-Za-z0-9_]*)", "captures": { "1": { "name": "storage.type.ludic" }, "2": { "name": "entity.name.type.ludic" } } }, { "match": "\\b(handler)\\s+([A-Za-z_][A-Za-z0-9_]*)", "captures": { "1": { "name": "storage.type.system.ludic" }, "2": { "name": "entity.name.function.system.ludic" } } }, { "match": "\\b(extern\\s+)?(fn)\\s+([A-Za-z_][A-Za-z0-9_]*)", "captures": { "1": { "name": "storage.modifier.extern.ludic" }, "2": { "name": "storage.type.function.ludic" }, "3": { "name": "entity.name.function.ludic" } } }, { "match": "\\b(const|var|let)\\s+([A-Za-z_][A-Za-z0-9_]*)", "captures": { "1": { "name": "storage.type.ludic" }, "2": { "name": "variable.other.definition.ludic" } } }, { "match": "\\b(state)\\s+([A-Za-z_][A-Za-z0-9_]*)", "captures": { "1": { "name": "keyword.control.state.ludic" }, "2": { "name": "entity.name.constant.state.ludic" } } }, { "match": "\\b(import)\\s+(?=\")", "captures": { "1": { "name": "keyword.control.import.ludic" } } }, { "match": "\\b(phase)\\s+(Start|Input|FixedUpdate|Update|LateUpdate|Render)\\b", "captures": { "1": { "name": "keyword.other.clause.ludic" }, "2": { "name": "constant.language.phase.ludic" } } }, { "match": "\\b(enter)\\s+([A-Za-z_][A-Za-z0-9_]*)", "captures": { "1": { "name": "keyword.control.enter.ludic" }, "2": { "name": "entity.name.type.scene.ludic" } } }, { "match": "\\b(spawn)\\s+([A-Za-z_][A-Za-z0-9_]*)", "captures": { "1": { "name": "keyword.control.spawn.ludic" }, "2": { "name": "entity.name.type.archetype.ludic" } } } ] }, "query": { "comment": "Inside a query's brackets a bare word names a component and {Word} is a filter that does not bind.", "begin": "\\b(query)\\s*(\\[)", "beginCaptures": { "1": { "name": "keyword.other.query.ludic" }, "2": { "name": "punctuation.section.brackets.begin.ludic" } }, "end": "(\\])", "endCaptures": { "1": { "name": "punctuation.section.brackets.end.ludic" } }, "patterns": [ { "match": "(\\{)\\s*([A-Za-z_][A-Za-z0-9_]*)\\s*(\\})", "captures": { "1": { "name": "punctuation.section.braces.begin.ludic" }, "2": { "name": "entity.name.type.tag.ludic" }, "3": { "name": "punctuation.section.braces.end.ludic" } } }, { "name": "entity.name.type.component.ludic", "match": "\\b[A-Za-z_][A-Za-z0-9_]*\\b" }, { "name": "punctuation.separator.ludic", "match": "," } ] }, "keyword": { "patterns": [ { "name": "keyword.control.ludic", "match": "\\b(if|else|while|for|in|match|machine|become|return|spawn|despawn|enable|disable|where|break|continue|new)\\b" }, { "name": "keyword.operator.logical.ludic", "match": "\\b(and|or|not)\\b" }, { "name": "keyword.other.clause.ludic", "match": "\\b(phase|query|on)\\b" }, { "name": "keyword.other.ludic", "match": "\\b(import|extern)\\b" }, { "name": "storage.type.ludic", "match": "\\b(program|property|model|enum|ui|const|var|let|fn|handler|entry|state)\\b" }, { "name": "support.type.primitive.ludic", "match": "\\b(int|long|fixed|bool|entity|str|ptr|byte|words|fixeds|ptrs|void)\\b" }, { "name": "constant.language.boolean.ludic", "match": "\\b(true|false|null)\\b" }, { "name": "constant.language.phase.ludic", "match": "\\b(Start|Input|FixedUpdate|Update|LateUpdate|Render)\\b" } ] }, "widget": { "patterns": [ { "comment": "widget types, recognised by the props or the child block that follow them", "name": "support.class.widget.ludic", "match": "\\b(panel|col|row|label|button|image|spacer)\\b(?=\\s*(\\{|[a-z][A-Za-z0-9_]*\\s*=|$))" }, { "comment": "widget props are written tight (id=Root); an assignment is written x = 1", "match": "\\b([a-z][A-Za-z0-9_]*)(=)(?!=)", "captures": { "1": { "name": "variable.parameter.widget.ludic" }, "2": { "name": "keyword.operator.assignment.ludic" } } } ] }, "builtin": { "patterns": [ { "comment": "the runtime surface — every name here resolves to rt_ in runtime/native", "name": "support.function.builtin.ludic", "match": "\\b(min|max|abs|clamp|seed|rng_range|rng_chance|fx|flr|map_size|map_row|tile|clear|present|fill_rect|frame_rect|put_px|text|text_int|font_load|text_ttf|text_w|text_h|image_load|draw_image|draw_image_scaled|draw_9slice|png_load|sprites_load|draw_sprite|draw_sprite_scaled|ui_build|ui_open|ui_tick|ui_render|ui_clicked|ui_set_text|ui_set_int|ui_focus|ui_focused|ui_visible|key|reg|set_reg|self|save|load|status|print|str|quit)\\b(?=\\s*\\()" }, { "comment": "compiler intrinsics — these lower straight to libc or the OS", "name": "support.function.intrinsic.ludic", "match": "\\b(bytes|words|resize|free|fill|offset|as_fixed|as_int|file_open|file_read|file_write|file_seek|file_tell|file_close|read_char|exit|arg_count|arg|file_stderr|file_stdout|is_windowed|game_title|win_open|win_poll|win_present|win_running|win_close)\\b(?=\\s*\\()" } ] }, "member": { "match": "(\\.)([A-Za-z_][A-Za-z0-9_]*)", "captures": { "1": { "name": "punctuation.accessor.ludic" }, "2": { "name": "variable.other.property.ludic" } } }, "call": { "match": "\\b([A-Za-z_][A-Za-z0-9_]*)\\s*(?=\\()", "name": "entity.name.function.call.ludic" }, "typename": { "comment": "components, archetypes, scenes and UI handles are Capitalised by convention", "name": "entity.name.type.ludic", "match": "\\b[A-Z][A-Za-z0-9_]*\\b" }, "operator": { "patterns": [ { "name": "keyword.operator.arrow.ludic", "match": "->|=>" }, { "name": "keyword.operator.range.ludic", "match": "\\.\\." }, { "name": "keyword.operator.bitwise.ludic", "match": "<<|>>|&|\\|\\^|~" }, { "name": "keyword.operator.comparison.ludic", "match": "==|!=|<=|>=|<|>" }, { "name": "keyword.operator.assignment.ludic", "match": "\\+=|-=|\\*=|/=|=" }, { "name": "keyword.operator.arithmetic.ludic", "match": "[+\\-*/%]" } ] } } }