Skip to content

Instantly share code, notes, and snippets.

@aaronfranke
Last active October 5, 2019 16:29
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save aaronfranke/89e5c7c13b3527b5210ae61c0e7b9caf to your computer and use it in GitHub Desktop.
Save aaronfranke/89e5c7c13b3527b5210ae61c0e7b9caf to your computer and use it in GitHub Desktop.
Prototype syntax for "Aaron Language", my dream programming language.
# This is a prototype syntax for "Aaron Lang".
# Inspired by C#, C++, GDScript, and Python.
# I doubt this would ever be a thing, but it shows what I would put in "the perfect language"
# The file is ".py" to make GitHub display the comments as a different color, but to be clear, this is nowhere close to Python.
# Comments are defined with "# " at the start.
# This is because "//" is used for math (floor division).
/* Inline and multi-line comments are also supported, but I only use the hash in this file */
# Methods can be in the global scope with no namespace.
# Main method is in the global scope and has no namespace.
# Main method returns int (like C++) and takes in a string array (like C#).
int Main (string[] args)
{
# C++ style indentation. Tabs standard for indentation, and language does not depend on indentation.
# Part of the language, also in global namespace. Writes to STDOUT.
Print("Hello World!");
# Method declarations do have a space before parenthesis.
# Method calls do NOT have a space before the parenthesis.
# This mostly just looks nice to me.
# Searches ahead automatically, no need for C++ forward declarations or header files.
int five = Math.Abs(-5);
# Constructors do not need the type repeated, just use "();". Type inferred from left.
# This is pretty much the opposite of what Python and GDScript do.
Math.Vector2i m = (1, 2);
# Namespaces can be added directly into functions, or other namespaces, or at the top of a file.
using Math;
# No need to write "Math.Vector2i", but it still would work.
Vector2i v = (1, 2);
five = Abs(-5); # Would need to be Math.Abs if there wasn't "using Math;" above.
# For polymorphism, you must create the object separately from its final container.
MySecret mySec = ();
Secret sec = mySec;
# Now sec contains a MySecret object.
# One would typically have separate a declaration anyway, inline polymorphism isn't very clear.
# C# code such as "Secret test = new MySecret();" seems confusing, strange, and niche to me.
# Decimal number literals can be written as "1.2" etc, no need for "1.2f".
Vector2 v = (1.2, 3.4);
}
namespace Math;
# Functions can exist directly in a namespace without a class, similarly to how Main exists without a class.
# Yet you are still able to create objects via classes and structs.
# This makes the language object-capable, while not requiring object-oriented for all code.
# Namespace functions take the place of "static class" in C# (but class members can still be static).
# I would rather have an "import-able" Math namespace that holds functions, than write "Math.Whatever" each time.
# See above with the "using Math;" line in Main if you're not sure of what I mean.
# C-like syntax, return type, name, arguments.
int Abs (int s)
{
return s < 0 ? -s : s; # Ternary operator
}
# Namespaces can also contain classes and structs.
struct Vector2
{
real x, y;
# Real is abstract and precision is controlled by compiler flags.
# For explicit precision, use "float32" or "float64" etc.
# There would probably also be "float" and "double" aliases for familiarity's sake.
real Length ()
{
return Sqrt(x*x + y*y);
# A call for Sqrt here checks for the existence of Vector2.Sqrt, Math.Sqrt, and global Sqrt.
# Locality takes priority. It searches Vector2 first, then Math, then global.
# If there's a conflict, you can be explicit: "this.Sqrt" or "Math.Sqrt" or "Global.Sqrt".
}
Vector2 (real X, real Y)
{
x = X;
y = Y;
}
}
# Structs are pass-by-value and don't use pointers or references.
# Classes are objects, fields for classes are references to them. Just like C++ and C#.
# Namespaces can be defined multiple times, so you can add your own code to Math.
# Note: A default Math namespace would be distributed with the language itself as a standard library.
struct Vector2i
{
int x, y;
# Int is abstract and size is controlled by compiler flags.
# For explicit size, use "int32" or "int64" etc.
real Length ()
{
return Sqrt(x*x + y*y); # Sqrt accepts reals, which the ints are implicitly casted to.
}
int LengthSquared ()
{
return x*x + y*y;
}
Vector2i (int X, int Y)
{
x = X;
y = Y;
}
}
# Note how Math.Vector2 is defined above as well.
# Similarly to multiple namespaces, classes and structs can be defined multiple times to add stuff to them.
# This allows adding code to classes and structs without creating a second class that extends it.
# Why: Does the standard library Vector2 not have a function you need? Don't re-write your own Vector2, just add to it!
# This also means that all Vector2 are the same and cross-compatible, no need to convert
# "YourProgram.YourVector2" to "Math.Vector2" before using it in the default Math namespace.
# Conflicting code additions could be handled by warnings, or by specifying
# an inheritance order, or requiring an "override" keyword.
struct Vector2
{
real LengthSquared ()
{
return x*x + y*y;
}
}
namespace Testing123
{
# Protected would be publicly visible, but its members are private by default.
# Private would be visible only in the namespace, and have private members by default.
# Internal would be visible only in the namespace, and have public members by default.
# Public would be publicly visible and have public members.
# Public is default unless the namespace itself has the an access modifier (relative to parent namespace).
protected class Secret
{
int a; # Private
public real b; # Public
# Like C# properties, access control can be imposed like this:
public int c
{
get; # Default getter, same as "get: return value;"
#get: return value + 1; # Would returns the value plus one if uncommented.
# Alternative syntax:
#get:
#{
#return value + 1;
#}
# Getters/setters can have multi-line code blocks with "{}"
set:
{
int temp = Abs(input); # "input" is the variable fed into setters, such as with "c = 5;"
value = temp; # "value" always means the variable's value. Only valid inside getters/setters.
}
}
# Basically, "c" here would be a variable that can't be negative,
# setting itself to the absolute value of what you give it.
# No particular reason for this, it's just a demonstration.
}
# Traits can add code to classes and structs. They are like C# interfaces, but with default implementations.
trait PrintStuff
{
void PrintHello ()
{
Print("Hello!");
}
# Yes this function is pretty useless. It's for simple demonstration purposes.
void PrintInt (int s)
{
Print(s); # Implicit cast to string.
}
void PrintNumber (real s)
{
# Primitive types can have methods called on them.
# Prints 3 decimal places, including trailing zeros.
Print(s.ToString("0.000"));
}
}
# Traits can extend other traits with ":".
trait PrintStuffAndFive : PrintStuff
{
void PrintFive ()
{
PrintInt(5);
}
}
# Traits are added to objects with a "can" keyword.
class MySecret : Secret can PrintStuff
{
void PrintB ()
{
PrintNumber(b);
# Functionality obtained via PrintStuff.
# "b" is a variable in the Secret class.
# Remember that this is the 2nd declaration of MySecret which adds code to the original declaration.
}
}
# Show warnings when files are using CRLF and/or UTF-8 w/ BOM.
# Also, compile warnings if 3+ newlines are found in the middle of a file.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment