Mindcode

repository·main·Indexed 41 days ago

https://github.com/cardillan/mindcode

A web application featuring a Java backend and a SvelteKit-based frontend. The project includes a specialized compiler, an annotation preprocessor, a CLI toolapp, and support for Schemacode. It utilizes a PostgreSQL database and can be deployed via Docker Compose or Heroku.

Tokens
150.7K
Snippets
480
Records
696
Agent score
47%

What's inside Mindcode

  1. Overview of Mindcode

    main

    Mindcode is a high-level procedural programming language designed for Mindustry Logic (mlog). It provides advanced features such as variable declarations, arrays (internal and external), conditional statements, loops, functions, modules, remote variables/function calls (sync/async), and atomic code execution.

    Mindcode compiles into optimized mlog code. It is available via a web application and a command-line compiler. It also supports Schemacode, an extension for creating complete Mindustry schematics from text files, which can be compiled into binary .msch files or text representations.

  2. Overview of Mindcode language features

    main

    Mindcode is a high-level procedural programming language designed for Mindustry Logic. It compiles into optimized mlog code, utilizing available instruction space to maximize performance.

    Key features include:

    • Core Language: Variable declaration, arrays, conditional statements, loops, and functions.
    • Advanced Control: Modules, remote variables, and both synchronous and asynchronous function calls.
    • Extensibility: Support for system libraries, user libraries, and the ability to extend the language to support new instructions from mods or different clients.
    • Tooling: Access via a web app, a command-line compiler, and integration with various IDEs and Mindustry itself.
  3. Overview of Mindcode Compiler Options

    main

    Compiler options affect how Mindcode source code is translated into mlog. They are categorized by their scope:

    • Global scope: Affects the entire program (e.g., setrate, target-guard).
    • Module scope: Affects a specific module (e.g., syntax). Note that all modules are implicitly strict.
    • Local scope: Affects specific blocks or functions (e.g., ipt, stack-depth, atomic-full-protection).
    OptionScopeSemantic Stability
    array-iteration-thresholdlocalstable
    atomic-full-protectionlocalstable
    atomic-merge-levellocalstable
    atomic-safety-marginlocalstable
    auto-printflushglobalstable
    emulate-strict-not-equalglobalstable
    enforce-size-limitsglobalstable
    iptlocalstable
    remarkslocalstable
    setrateglobalstable
    stack-depthlocalstable
    syntaxmodulestable
    target-guardglobalstable
  4. Overview of Mindcode Project Modules

    main

    Mindcode is composed of several specialized modules:

    • mindcode-annotations: Annotation preprocessor for automatic code generation.
    • mindcode-compiler: Contains the Mindcode compiler (grammar, parser, AST builder, code generator, optimizer) and a Processor emulator for running mlog code.
    • mindcode-exttest: Tool for testing the compiler and emulator under various settings.
    • mindcode-samples: Mindcode and Schemacode samples for the web application.
    • mindcode-schemacode: Grammar definition, compiler, and decompiler for Schemacode.
    • mindcode-toolapp: Command-line interface (CLI).
    • mindcode-webapp: The web application frontend.
  5. What is Schemacode?

    main

    Schemacode is a specialized definition language used to describe the structure of Mindustry Schematics. It can be compiled into binary .msch files or text representations.

    Key features:

    • Supports almost all Mindustry schematic features (specifically all Serpulo technology features).
    • Allows full configuration of logic processors using either native mlog or Mindcode.
    • Supports injecting source code from external files via the command line tool.

    Workflow Tip: For complex designs, it is often easier to build the schematic in Mindustry, export it, and then use the command line tool to decompile it into a valid Schemacode representation.

  6. How the `wait` instruction works in Mindustry 8

    main

    In Mindustry 8, the wait instruction has two key behaviors:

    1. Zero-argument wait: Skips the rest of the current frame but is not executed again on the next frame.
    2. Yielding wait: When the instruction yields execution (waits for a specified time), the accumulator is not decreased.

    This ensures that when a code section waits, the accumulator is guaranteed to have enough capacity to execute the corresponding number of instructions (based on the processor's current instructions-per-tick) uninterrupted during the next update. This can be used to ensure code sections execute atomically.

  7. Link blocks to a processor

    main

    There are three primary ways to link blocks to a processor in Schemacode:

    1. Linking by Block References

    Use block labels or patterns to link multiple blocks at once.

    • Simple link name: links <block-reference> as <link-name> end. If the reference resolves to multiple blocks, it causes an error.
    • Array labels: Using a local array label as a link name generates unique link names for each block resolved by the reference.
    • Automatic derivation: If no name is provided, the link name is derived from the block label:
      • If the label contains a dash (-), the part after the first dash is used.
      • Otherwise, the entire label is used.
    • Prefixes: You can use prefixes (e.g., p-*) to group blocks and allow multiple processors to match them using pattern matching.

    2. Linking by Position

    Specify links using coordinates. Relative coordinates are evaluated against the processor block.

    • Syntax: (x, y) as <link-name> or +(x, y) as <link-name>.
    • Virtual Links: Use the virtual keyword (e.g., +(2, 0) as message4 virtual) to create links to tiles that may be outside the schematic or currently empty. Any block subsequently placed on that tile in the Mindustry world will be automatically linked.

    Instead of literal names, you can use symbolic names that the Mindcode compiler resolves. This allows the same block to be linked to different processors using the same symbolic name without index conflicts.

    • Requirement: Every symbolic link name used in the links section must be declared in the Mindcode source code using the linked(@type) name; syntax.

    Link Name Requirements:

    • Literal names: Must follow the pattern of the block type's last part + a number (e.g., drill1 for @laser-drill).
    • Symbolic names: Must be valid Mindcode identifiers and must not conflict with possible literal link names.
    • Uniqueness: Link names must be unique within a single processor, and each block can be linked at most once per processor.
    @micro-processor at (0, 0) processor
        links
            p-* 
            message1
            (4, 0) as cell1
            (2, 0) as cell2 virtual
        end
        mlog = ""
    end
    
    p-switch1:  @switch  at (1, 0)
    message1:   @message at (3, 0)
    @memory-cell at (4, 0)
  8. Use symbolic names for schematic links in Mindcode 3.17

    main

    Instead of using literal link names (which are assigned numerical indexes by the compiler), Mindcode 3.17 allows assigning symbolic names to links in both Schemacode and Mindcode.

    Benefits of symbolic names:

    • Information: Names carry meaning about the block's purpose.
    • Traceability: The same name is used in Schemacode and Mindcode, making it easy to find references.
    • Reliability: Avoids potential link mix-ups caused by numerical index assignment bugs in Mindustry.
    • Simplicity: Eliminates the need to manually manage different indexes for the same block across different processors.
  9. Optimizing chained if-else (elsif) statements

    main

    In Mindcode, elsif statements are treated as nested else branches. The optimizer applies standard if-expression optimizations to these nested structures, which can significantly reduce the number of instructions compared to unoptimized nested if blocks by minimizing temporary variable assignments.

    y = if x < 0 then
        "negative";
    elsif x > 0 then
        "positive";
    else
        "zero";
    end;
    print("value is ", y);
  10. Understand bitwise `or` and logical `and` behavior

    main

    Bitwise and logical operations have specific conversion rules that can lead to unexpected results with floating-point numbers.

    Bitwise or (op or): Operates on integers. Non-zero values less than one are converted to 0. Consequently, a small non-zero value might be treated as false in a bitwise operation.

    Logical and (op land): Operates on non-zero values. Operands are not converted to integers; any value strictly non-zero is considered true.

    Comparison Example:

    set a 0.5
    set b 0.5
    op notEqual x a 0         # x = 1 (true) because a is non-zero
    op or y a b               # y = 0 because 0.5 is converted to integer 0
    print x                   # prints 1
    print y                   # prints 0
    
    set a 0.00000001
    set b 0.00000001
    op notEqual x a 0         # x = 1 (true)
    op land y a b             # y = 1 (true) because a and b are strictly non-zero
    print x                   # prints 1
    print y                   # prints 1
    set a 0.5
    set b 0.5
    op notEqual x a 0         # set x to 1 if a is nonzero (i.e., true)
    op or y a b               # y = a or b
    print x                   # prints 1
    print y                   # prints 0
    
    set a 0.00000001
    set b 0.00000001
    op notEqual x a 0         # set x to 1 if a is nonzero (i.e., true)
    op land y a b             # y = a and b
    print x                   # prints 1
    print y                   # prints 1