Git Product home page Git Product logo

catspeak-lang's Introduction

% pairs:    [-katsaii,k-atsaii,ka-tsaii,kat-saii,kats-aii,katsa-ii,katsai-i,katsaii-]
% prefixes: [,k,ka,kat,kats,katsa,katsai,katsaii]
% suffixes: [katsaii,atsaii,tsaii,saii,aii,ii,i,]

name("katsaii").

?-
  name(Name),
  findall(Prefix-Suffix, string_concat(Prefix, Suffix, Name), Pairs),
  pairs_keys_values(Pairs, Prefixes, Suffixes),

  write("pairs:    "), write(Pairs), nl,
  write("prefixes: "), write(Prefixes), nl,
  write("suffixes: "), write(Suffixes).

Try it online!

catspeak-lang's People

Contributors

jujuadams avatar katsaii avatar localinsomniac avatar nonk123 avatar tabularelf avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar

catspeak-lang's Issues

Static constructor methods not respected in scope

I’ve mostly moved over to catspeak v3 in my current project… Came across a few oddities that I wasn’t getting previously.
But from my testing, it seems that catspeak isn’t fond of static methods from a constructor.

If I have a constructor that I pass to Catspeak as a function like

Catspeak.addFunction("Construct", function() {
    return new Construct();
});

And Construct has

function Construct() constructor {
    str = "";
    
    static add = function(_str) {
        str += string(_str);
    }
}

Trying to do this in Catspeak results in it trying to access the compiled Catspeak program as the scope, and not the constructor instance. Hence causing an error/modifying the wrong instance.

var _inst = Construct();
_inst.add("Woo!"); 

Resolve technical debt

A lot of technical debt has been gathered, now would be the time to re-organise the API.

Improve documentation format

  • Add actual markdown support.
  • Separate library documentation from the more in-depth docs, such as getting started and semantic/syntax details.

Consider adding user-defined functions

This could potentially cause breaking changes to the compiler and runtime, especially if it becomes possible to call catspeak functions from within GameMaker.

The syntax could resemble the following:

set add : fun a b {
    return : a + b
}

The two largest issues with adding functions are:

  • Whether Catspeak functions should be callable by GameMaker code
  • How to maintain multiple VM processes if this is the case

If the values returned from Catspeak functions are needed immediately by GML code, then that defeats the purpose of Catspeak being executed over multiple steps.

Functions that originate in Catspeak lose the ability to set self/globals structs when passed back into GML

Consider

open()
callback(fun() {
    //do stuff
})
close()

On the GML side: open() creates a struct, callback() assigns a callback to that struct, and close() drops the reference to the struct.

In order to get the callback to execute in the intended scope, which would be the created struct, I'd need to call .setSelf() and/or .setGlobals() on the method that Catspeak passes into the bound GML function for callback().

However, this is not possible as it seems like the returned method lacks the necessary setter methods for itself.

UTF8 support

Doing this may slow down lexing, but I reckon it's worth it. I could always add an option, to disable it

Implement method call semantics

Consider the following definition:

let bunny = {
  n : 0,
  speak : fun() {
    self.n = it + 1
    "purr"
  },
}

The line bunny.speak() should run the speak function in the scope of the bunny struct.

Add proper demo object

Right now running the development project results in a blank project with non-obvious pop-ups. This is fine for development but intimidating for any contributors.

Add custom presets

Right now, Catspeak environments have built-in presets for adding GML functions and constants easily. I would like for a way for users to extend this with custom string keys:

catspeak_preset_add("my-custom", function (env) {
  env.addFunction("rgb", make_colour_rgb);
});

And then apply it like

Catspeak.applyPreset("my-custom");

Simplified API

The catspeak_execute and catspeak_compile_buffer functions are useful, but becomes a bit exhausting for simple "compile-and-execute" use cases, such as loading an initialisation script from a file that only gets executed once.

Consider adding a new catspeak function, which should encapsulate this behaviour:

catspeak("1 + 2").andThen(function(result) {
  show_message(result);
});

If the first argument is not a string, then it is assumed to be a buffer:

catspeak(buff).andThen(function(result) {
  show_message(result);
});

The second parameter to this function will determine the namespaces to use when resolving global constants. For example, adding a particle function to a namespace:

catspeak_prelude_add_function("part", "create", part_type_create);

and then making that namespace visible to the compiler:

catspeak("part::create()", "part").andThen(function(result) {
  show_message(result);
});

Syntax to be decided.

Catspeak -> GML transpilation

Write a program to convert Catspeak code into GML code, maybe for better interop/faster execution of static code.

Implement CSS colour constants, hexadecimal literals, and binary literals

Is your feature request related to a problem? Please specify.

You dare ask ME how to write an issue on MY own repository?

What is your feature request?

Add #FFF, 0xFFFFFF, and 0b0110 syntax to the language.

Have you found an alternative solution? What have you been doing?

grr kitten ur so sussy!
grr kitten ur so sussy

Add the ability to break out of multiple loops

Catspeak currently supports break and continue control flow structures, but only for a single loop.

This could be enhanced either by adding goto and labels, or by allowing break and continue to accept an optional argument that indicates how many loops to exit:

while true {
    while true {
        break 2
    }
}

break would then be equivalent to break 1.

Add unit tests

The previous version of Catspeak had some sense of unit tests, this version should too.

Implement "foreach" loops

Catspeak currently has while-loops, but lacks a method of easily iterating over collections. This could take the form of a typical for-in-loop found in other languages

set arr [1; 2; 3]
for arr.[i] value {
    print i
    print value
}

or they could resemble Python list comprehensions

set arr [1; 2; 3]
set arr' : [value * value for arr.[i] value]

I am leaning towards the first option because it allows for a sequence of statements to be performed on the inner values.

Export and load Catspeak code in a binary format

This would be the so-called "pre-compilation" feature listed in the README.md file and docs. The binary format is undecided right now, but it would require refactors to how global variables and standard library functions are loaded by programs.

Implement short-circuiting `and` and `or` operators

These would be special keywords, potentially with the same precedence as their && and || counterparts. Implementing these operators may complicate the parser ever so slightly, but it should be manageable.

Rendered:

if (a or b and c) {
  -- cool!
}

would be equivalent to this code:

let condition = do {
  let t1 = a;
  if (t1) {
    t1
  } else {
    let t2 = b;
    if (t2) { c } else { t2 }
  }
}
if (condition) {
  -- cool!
}

Proper futures system for Catspeak processes

Refactor CatspeakProcess to allow the following code to be written:

catspeak_compile_string("hi").andThen(function(ir) {
    return catspeak_execute(ir, []);
}).andThen(function(result) {
    show_message(result);
}).catchError(function(err) {
    show_message("oh no");
}).withTimeLimit(10);

With the current code, this may look like:

global.errorHandler = function(err) {
  show_message("oh no");
};
catspeak_compile_string("hi").andThen(function(ir) {
  catspeak_execute(ir, []).andThen(function(result) {
    show_message(result);
  }).catchError(global.errorHandler).withTimeLimit(10);
}).catchError(global.errorHandler).withTimeLimit(10);

which is clearly exhausting and ugly to look at.

func.setSelf(<instance>) leads to error due to GM's native is_struct() failing

The .setSelf() method on functions returned by Catspeak.compileGML() uses is_struct() to verify whether the provided target is valid (when CATSPEAK_DEBUG_MODE is set to true). Unfortunately, is_struct() returns false if passed an instance struct which then causes .setSelf() to error out despite an instance struct being a valid target.

Issue is easy enough to repro. Ensure CATSPEAK_DEBUG_MODE is set to true and then execute the following in the scope of an object instance:

func = Catspeak.compileGML(_asg);
func.setSelf(self);

I'm testing on IDE v2022.0.0.19 Runtime v2022.0.0.12 so this is_struct() behaviour might have changed in newer versions.

Add in a way to check if a global exists from CatspeakFunction.

We have .getGlobal() and .setGlobal(), which both are great! But there's no way to check if a specific global does exist or not.
Adding in a way would at the very least make it easier on my end to check for specific globals, rather than relying on undefined.

More descriptive runtime error messages when in debug mode

Ran into a confusing bug when trying to call this code:

draw_text(10, 10, string([1, 2]));

I had forgotten to add string as a function to the environment. Catspeak threw this error out:

___________________________________________
############################################################################################
ERROR in
action number 1
of Draw Event
for object Object1:

script_execute_ext argument 1 incorrect type (undefined) expecting a Number (YYGI32)
 at gml_Script___catspeak_expr_call__ (line 841) -         return script_execute_ext(calleeIdx, args_);
############################################################################################
gml_Script___catspeak_expr_call__ (line 841)
gml_Script_anon___catspeak_expr_call___gml_GlobalScript_scr_catspeak_codegen_25249___catspeak_expr_call___gml_GlobalScript_scr_catspeak_codegen (line 837) -     var args_ = array_map(args, function(f) { return f() });
gml_Script_array_map (line 8) -         _new[@ _i] = _function(_array[_i]);
gml_Script___catspeak_expr_call__ (line 837) -     var args_ = array_map(args, function(f) { return f() });
gml_Script___catspeak_function__ (line 668) -         value = program();
gml_Object_Object1_Draw_0 (line 2) - func();

Figured out what was going on but it'd good to have a clearer error message that'll direct me to the offending function call.

env.applyPreset() needs a clearer error message

env.applyPreset() should be something clearer than "you have likely encountered a compiler bug". As it makes it harder to narrow down the exact issue.

For example in my case, I commented out CatspeakPreset.GML, but forgot to include the comma, which passed in undefined (as per an optional argument skip, not a specific Catspeak issue there of course), and I was confused when it gave me that error and I was double checking my Catspeak code.

Catspeak.applyPreset(/*CatspeakPreset.GML*/, CatspeakPreset.MATH)

Customisable language keywords

This is a bit of an esoteric feature, but exposing a method of modifying the compiler internals in a stable way, such as which identifiers correspond to keywords. Maybe the catspeak_config function can be utilised for this:

catspeak_config({
  "keywords": { "func" : CatspeakToken.FUN },
});

Replace Catspeak sessions with processes in order to reduce bloat

The current runtime environment is okay, but after some testing code ends up fairly bloated, and doesn't blend well with multiple VMs running simultaneously. In order to fix this issue, instead of creating individual Catspeak sessions per task, a global singleton session should exist which can spawn other processes. A simple scheduler would be implemented that would divide time between all active processes.

The advantages of this approach are:

  • Reduce code bloat
  • Multiple VM processes concurrently
  • Easily extendable with multi-step processing
  • Opens the doors to function definitions as described in #4 because processes are managed centrally
  • Less pressure on developers/users of the language to manage Catspeak sessions

.removeFunction() method on environments

Whilst building Catspeak Live, I'm finding that there are situations in which I'd like to remove functions from an environment as sources files are removed from the cache/index. I've hacked in a function to do that myself inside of Catspeak but it might be a useful feature to have in general.

See also: .removeConstant() .removedKeyword()

Defining structs without leading comma at end crashes

Was experimenting with structs, when I've noticed something odd.
This bit of code here

var asg = Catspeak.parseString(@'
	
return {
	foo: "bar",
	a_number: 0,
	a_string: "Hello World!"
}
');
func = Catspeak.compileGML(asg);
var result = func();
show_debug_message(json_stringify(result, true));

Is causing Catspeak to crash. Unless I add a comma at the end. Then it works just fine?

return {
	foo: "bar",
	a_number: 0,
	a_string: "Hello World!",
}

crash.txt

`else if` throws an error

What is the bug? How did it happen?

Executing the following Catspeak script ...

a = 1
if (a == 1) {

} else if (a == 2) {

}

... throws the following error

___________________________________________
############################################################################################
ERROR in
action number 1
of Create Event
for object oCatspeakTest:

Catspeak v3.0.0: in a file at (line 5, column 10) when parsing -- expected opening '{' at the start of 'else' block, got token '(' (0)
 at gml_Script___catspeak_error (line 25) -     show_error(msg, false);
############################################################################################
gml_Script___catspeak_error (line 25)
gml_Script_anon_CatspeakParser_gml_GlobalScript_scr_catspeak_parser_21137_CatspeakParser_gml_GlobalScript_scr_catspeak_parser (line 597) -             __catspeak_error(dbg, " -- ", msg, ", got ", __tokenDebug());
gml_Script_anon_CatspeakParser_gml_GlobalScript_scr_catspeak_parser_7533_CatspeakParser_gml_GlobalScript_scr_catspeak_parser (line 203) -             __ex("expected opening '{' at the start of '", keyword, "' block");
gml_Script_anon_CatspeakParser_gml_GlobalScript_scr_catspeak_parser_3645_CatspeakParser_gml_GlobalScript_scr_catspeak_parser (line 150) -                 __parseStatements("else");
gml_Script_anon_CatspeakParser_gml_GlobalScript_scr_catspeak_parser_2441_CatspeakParser_gml_GlobalScript_scr_catspeak_parser (line 96) -             result = __parseExpression();
gml_Script_anon_CatspeakParser_gml_GlobalScript_scr_catspeak_parser_1931_CatspeakParser_gml_GlobalScript_scr_catspeak_parser (line 63) -         __parseStatement();
gml_Script_anon_CatspeakEnvironment_gml_GlobalScript_scr_catspeak_environment_3622_CatspeakEnvironment_gml_GlobalScript_scr_catspeak_environment (line 97) -             moreToParse = parser.update();
gml_Script_anon_CatspeakEnvironment_gml_GlobalScript_scr_catspeak_environment_4291_CatspeakEnvironment_gml_GlobalScript_scr_catspeak_environment (line 110) -         return Catspeak.parse(buff);
gml_Object_oCatspeakTest_Create_0 (line 23) - var _asg = Catspeak.parseString(@'

What was the expected behaviour?

no crash :(

Version

3.0.0-beta3

`or` and `and` operators not working

What is the bug? How did it happen?

Seems that or and and do not work in Catspeak currently. Upon compiling a function, the following error is returned.

Variable CatspeakParser.op(100050, -2147483648) not set before reading it.
at gml_Script_anon_CatspeakParser_gml_GlobalScript_scr_catspeak_parser_8905_CatspeakParser_gml_GlobalScript_scr_catspeak_parser (line 260) -                 result = asg.createOr(op, lhs, rhs, lexer.getLocation());

Upon further investigation, seems that op wasn't meant to be there. And neither or nor and were defined under __productionLookup.

What was the expected behaviour?

This code here

foo = "bar";

if (foo == "boot" or foo == "bar") {
	show_debug_message("Tada!!");
}

Should compile and compare whether foo is boot or bar.
Note: show_debug_message() was added in as a function via .addFunction

Version

3.0.0-beta3

Implement `new` keyword in Catspeak

Is your feature request related to a problem? Please specify.

Even though Catspeak recognizes the new keyword (see scr_catspeak_lexer), it hasn't been implemented yet and therefore has no functionality. This prevents users from creating new structs through constructors in their Catspeak code without adding wrapper functions.

What is your feature request?

See title.

Have you found an alternative solution? What have you been doing?

If new was implemented, the solution would look like this:

GML:

function Construct() constructor {}
Catspeak.addFunction("Construct", Construct)

Catspeak:

let _inst = new Construct()

Since Catspeak 3 Beta 3 (the latest pre-release at the time of writing this) doesn't have new, creating constructors requires adding wrapper functions to Catspeak like so:

GML:

function Construct() constructor {}

Catspeak.addFunction("Construct", function () {
    return new Construct()
})

Catspeak:

let _inst = Construct()

Feature to pick up arguments passed into a compiled Catspeak function

Couldn't find this one in the old v2 docs, but it'd be handy to be able to pass arguments into a Catspeak compiled functions and pick them up inside e.g.

func = Catspeak.compileGML(_asg);
func(x, y);
draw_text($param0, $param1. "Hello");

Or something similar. We can achieve a similar effect by calling .setSelf() on the function but direct argument passing would be easier to use in many situations.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.