A programming language that spins off of this question: "Is it possible to make a programming language without any keywords?"
The answer so far: sortof, but not really. It depends if you count operators as keywords, and if you count built-in functions.
There is also going to be support for many (if not all) of the aspects of LOP (Language Oriented Programming), what I regard to be the next programming paradigm. But it also has support for OOP, via syntax extentions (thanks to LOP ), and/or it's built-in object prototyping.
It is designed to make using functions easy-peasy. Without syntax extentions, there are 6 (ish) syntaxes to define a function, and all functions are first-order, so they can take other functions as arguments.
I'm actually looking for help with the initial runtime. Once that's done, it'l be bootstrapped.
Here's a code sample for those interested:
/**
* An implimentation of else and elif using only if
*/
=<(b,f) {
if(b,f);
state=b;
out={};
out.elif=(b,f) {
state=state.or(not(b));
if(not(state),f);
=<out;
};
out~out.elif;//Overload out to take elif
out.else=f=>{
if(not(state),f);
};
out~out.else;
=<out;
};
These features are core to the design, and are very unlikely to change very much.
- No keywords
- Also try to avoid things like them. (Operators and Types are to be used sparingly)
- A sleek, secure way of having per-file syntax overloading.
- Syntax modules included at the beginning of the file, much like imports
- Functions are call by value
- Everything is a function
- Any operator may be applied to any variable, at all.
- EX: while
7.times(10)
returns70
, a function that returns 7 multipled by a function that returns 10 returns a function that returns the result of that operator applied to each value, respectively.
- EX: while
retSeven=()=>7;
retTen=()=>10;
resultGetter=retSeven.times(retTen);
endResult=resultGetter();
- The Chameleon Programming Language Standard
- Table of Contents
- The compiler
- Stages
- Runtime
- Current state
- Plans
- Variables
- Functions
- Defining functions
- No args
- No args One line
- One Arg
- One arg One Line
- Multi-arg
- Multi-arg One line
- Calling functions
- Scoping
- When var names collide
- Scoping
- Returning
- From inside a one-liner
- From a block function
- Defining functions
- Operators
- Other features
- Syntax
- Comments
- Typecasting
- Reserved functions
- throw
- while
- if
- import
- useSyntax
- declareSyntax
- Regexp
- Resources
- [7/11] The Chameleon Programming Language Standard
- Table of Contents
- The compiler
- Variables
- Functions
- Operators
- [1/3] Types
- Type inference
- Type functions
-
Func
-
Bool
-
Int
-
Char
-
Arr
-
Str
-
- Casting
- Libraries
- Using libraries
-
import
- Some example libraries
- IO
- Vector
- Regexp
-
- Writing libraries
- Using libraries
- Overloading
- Overloading functions
- Overloading types
- Overloading operators
- Overloading syntax - (points to dedicated section)
- Syntax Extention
- Using a syntax module
- Common modules
- Writing a syntax module
- Using a syntax module
- Resources
- Feed source code (call this file A) into tokenizer (outputs a stream). Go to step 2.
- Feed token stream into parser. If an import or syntax extention is found, go
to step 2.1, or else go to step 3.
- Grab the file that the import or syntax extention requires, and pass that into step 1. (call this file file B) If it's a syntax module, go to step 2.3, or else go to step 2.2.
- Get the entire Parse tree for file B, and insert it into the proper node on file A's parse tree. Go to step 3 (not to be confused with step 2.3).
- Run File B through the interpreter (not the JIT compiler). It may modify the token list, parse tree generator, Ast tree generator, interpeter, AST tree reverser, parse tree reverser, and or the token reverser. This modification only applies to this local file A (not file a's parent, if this is multiple levels deep, and not file B). Continue to step 3.
- Convert the parse tree into an AST tree. If file A is being interpreted run the file, or else continue to step 4.
- Convert the AST tree into a parse tree for the output language (or language family) Continue to step 5.
- Convert the parse tree into a token stream for the output language (or language family). Coontinue to step 6.
- Convert the token stream into the transpiled code for the output language. (Most often this is LLVM, but I've been thinking about output to JavaScript, JVM, and a few others). If the compiler is in JIT mode, run the file.
As the standard output of the file is planned to be LLVM code, it will have an enviroment simmilar to that one, but I am concidering having JVM and/or JavaScript as options for target languages.
The exeption to this is when it's in interpeter mode, but this should function about the same.
There are multiple parallel attemps to reach a working end-goal.
- The cpp implimentation is the oldest one. It right now can only just barely handle some comments, sometimes. I'm not likely to continue pursuit with this one, I'm just using it for reference, and will most likely remove it.
- The chaml one is 75% done, but once I realised I made a few critical mistakes
(such as not actually knowing what a lexer is and what a parser is), I decided
to stop for awhile.
- In the lib directory are libraries that I plan to have availiable. Many are highly experimental.
- I plan on re-writing this once a different implimentation starts working.
- flex_bison was going to be the offical first language compiler/interpreter/ whatever_the_heck_I_actually_got_out_of_it, but as I am not super familiar with C or C++ I am looking into alternatives. I actually can do basic math in the library as if it was actually done, but it feels unreliable.
- java is my potential replacement for flex_bison. Very little progress, but as I know the datatypes well enough, I should be able to make this work.
GET IT WORKING
I personally don't have any plan but this, and what is in the "Current state" section
All variables are functions. When set with the =
operator, it is overwritten
with the value on the right side. When set with the ~
(tilda) operator, the
caller is overloaded.
Naming conventions are identical to JavaScript; they may contain any number,
upper or lowercase letter, or these: $_
. They cannot start with a number.
newVar=3; // number
anotherVar=()=>3; //function returning a number
_yetanoth3rVar='c'; // this is just a char, but can be cast to and from a number
arrofnums=[3,5,3,2,5,64,5,64,3];//cant change len, but you can replace the value
$another="This is shorthand for an array of chars";
theLast1=true;//And here's a bool.
Names may include any character otherwise not used in any syntax.
Uses call/pass by value.
Supports 6 ways of declaring functions, listed below
anyVariableHere={
//do something upon invoction
};
anyVariableHere=()=> 72;// return 72
anyVariableHere= in => {
=<in.times(2); // return the arg times two
};
anyVariableHere= in => in*2;//a single line is treated like a code block
anyVariableHere= (a,FEW,dif_ferent,var5,h$r3) => {
//The => is optional when inbetween an endparen and an opening curly
=<a.plus(FEW).plus(dif_frent).plus(var5).plus(h$er3);
};
anyVariableHere= (a,FEW,dif_ferent, var5,h$r3) => a.plus(FEW).plus(dif_frent).plus(var5).plus(h$er3);
a=()=>1;
b=a=>a.plus(1);
c=(a,b)=>a.plus(b);
//Call a
a(); // returns 1
//call b, passing a value. (if a var, it's duplicated)
b(3); // returns 4
c(3,7); // returns 10
The ~
(tilda) operator makes the function on the right the function to call
given its number of arguments and the args that were passed in.
tog=true;//A value that myF will be modifying
myF={//If no arguments are given, toggle `tog`
if(tog,{
tog=false;
},{
tog=true;
});
};
myF~firstArg=>{//If one argument is given, unconditionally set `tog` to that
tog=firstArg;
};
a=0;
myF~(ifT,ifF){//If two arguments are given, set `a` to the first if `tog` is true, and the second if it is false
if(tog,{
a=ifT;
},{
a=ifF;
});
};
myF();//Toggle tog
myF(true);//Set tog to true
myF(10,20);//set a to 10 if tog is true, and set a to 20 if tog is false
//`a` should now be equal to 10.
//can't change or read any vars here
a=1947;
//`a` is the only var that can be changed or read here
theFunc=(e)=>{
//`a`, `theFunc` and `e` are the only vars that can be changed or read here
b=28142;
//`a`, `theFunc`, `e` and `b` are the only vars that can be changed or read here
theFunc.c=4234;
//`a`, `theFunc`, `theFunc.c`, `e` and `b` are the only vars that can be changed or read here
theFunc.p=()=>b;
//`a`, `theFunc`, `theFunc.c`, `theFunc.p`, `e` and `b` are the only vars that can be changed or read here
e=e.plus(1);
};
//`a` and `theFunc` are the only vars that can be changed or read here
d=324;
//`a`, `theFunc` and `d` are the only vars that can be changed or read here
theFunc.c=7;
//`a`, `theFunc`, `theFunc.c` and `d` are the only vars that can be changed or read here
v=99;
//`a`, `theFunc`, `theFunc.c`, `d` and `v` are the only vars that can be changed or read here
theFunc(v);
//`a`, `theFunc`, `theFunc.c`, `theFunc.p`, `d` and `v` are the only vars that can be changed or read here. `b` may be indirectly read through calling `theFunc.p`, but cannot be changed here
Aditionally, functions can be defined within other functions. If you can read a function, you can run it. As they are stored within variables, they follow the same scoping when it comes to running the function.This also applies to variables within functions within functions:
//no vars can be read here
outerFunc={
//`outerFunc` is the only var that can be changed or read here
innerFunc={
//`outerFunc` and `innerFunc` are the only vars that can be changed or read here
a=true;
//`outerFunc`, `innerFunc` and `a` are the only vars that can be changed or read here
};
//`outerFunc` and `innerFunc` are the only vars that can be changed or read here
};
//`outerFunc` is the only var that can be changed or read here
Sometimes, variable names are unintentially reused by devs. Here's an example of functional, yet poorly written code.
conflicingName=849234;
funcName=conflictingName=> conflicingName();
funcName(() => 21); //returns 21
anotherName=(conflicingName) => {
=<conflictingName.times(10);
};
k=3;
anotherName(k)//returns 30
//conflictingName is still 849234
returnsNumber1=()=>1;
returnsArgTimesTwo=arg=>arg.times(2);
returnsTheSumOfArgs=(a,b)=>a.plus(b);
returnsNumber1={
=<1;
};
returnsArgTimesTwo=arg=>{
=<arg.times(2);
};
returnsTheSumOfArgs=(a,b) => {
=<a.plus(b);
};
- SET
=
- OVERLOAD
~
(Tilda. Sets the internal "caller" of the following closure's arg len to the following closure) - RETURN
=<
- LAMDA
=>
- SUBPROPERTYACESS
.
Types are functions where have this behavior given the number of args,
Zero returns the default value, if applicable. (Think of it like a default constructor)
One argument returns a duplicate of this type if it is already this type.
Elsewise, call that class's class.to.
then whatever this class is.
EX: class.to.Foo
inside of a class called Foo
.
Any more are arguments type specific.
These are the default type constructors
Func
Int
- has mathmatical methods on children
plus
minus
times
div
mod
- also has boolean returners on children
gt
greater thanlt
less thangte
greater than or equal tolte
less than or equal to
- other
eq
- has mathmatical methods on children
Char
- getCode returns the charcode
- other
eq
Array
- size returns the size
- other
eq
Bool
- public
not
function returns inverse of passed in boolean - has binary logic functions/methods
and
or
xor
Exclusive or
- other
eq
- public
Str
Strings are just arrays of chars. Shorthand for['h','i']
is"hi"
.
- Object inheritance
- The core components are provided (via some built-in prototyping), but can be improoved with a library.
- Keywords, inline xml, obj syntax sugar all to be syntax modules.
Make most operators a syntax module.
- keywords
- A full explicit type system
- inline xml
- lazy function calling (from perspective of caller)
- A lib to make ifs C-style
- a lib to make strings their own datatype
- a lib to make bools an instance of Int (0 or 1)
- a lib to generate a documentaiton markdown file using comments
- could interact with the keywords lib idea and its children
- could interact with the AST too
//Single-line C++ style.
/*
Along with muli line C style are both supported
*/
//* single line comments are evaluated first
And_thus="this line is still reached and evaluated";
/**
* This type of comment is intended documentation for smooth integration with
* your IDE, if it supports it. Must be valid markdown, but type indicators
* may be accepted.
*
* No IDE's are known to support the language more then they would a .txt file.
* Replace this with a labled list of known IDE's in the future. If the count
* is greater then 20, remove this list.
*/
Comments are preserved as long as possible, with few exeptions (ex: interpeting mode) throughout the compiling process. This means it should be possible to make comment dependant functionality
Variables are never cast automatically.
To cast use the constructor like so:
joinOfStringAndNum="The number is ".plus(String(37))
One can overload casting by doing something like this:
//Overload casting of Array to Boolean in all cases
Array.to.Boolean={
//Return what you want the value to be. NOTE: BROKEN DUE TO LACK OF CURRENT VAL ACCESS!
};
//Overload instance only
myNumber=4234
myNumber.to.Char={
//Same as before, return what you want the value to be. NOTE: BROKEN DUE TO LACK OF CURRENT VAL ACCESS!
};
- To
Boolean
Boolean
duplicate of original booleanInt
true only if equal to0
or-0
Array
If array is len of 1 and it is a bool, then that bool, else error thrown:Casting error: Cannot cast Array to Boolean
- To
Char
Bool
't'
if true,'f'
if falseChar
duplicate of original charInt
local charcode conversion to char. If invalid, throw sensible error likeCasting error: Cannot cast Int(
insert num here) to Char
as it is value dependant.Arr
If array is len of 1 and it is a char, then that char, else error thrown:Casting error: Cannot cast Array to Char
- To
Int
Bool
0
if true,1
if falseChar
local charcode conversion to int. If invalid, throw sensible error likeCasting error: Cannot cast Char(
insert char here) to Integer
as it is value dependant.Int
duplicate of original numArr
If array is len of 1 and it is a number, then that number, else error thrown:Casting error: Cannot cast Array to Int
Str
If the string is what would pass for a valid in-line literal of any type (decimal, hex, etc.) then resolve it, elsewhise, throw:Casting error: Cannot cast String(
insert string here) to Int
- To
Arr
- empty, array len of 0
Bool
"True"
if true,"False"
if false.Char
The char is turned into a string with len of 1Int
empty array of the length of that number.- Optional 2nd arg: what to fill it with.
- If not enough memory, error thrown:
Casting error: Cannot cast Int(
insert num here) to Array
Array
duplicate of origianl array
- To
Func
all cases: return a function that returns the input, unless it is empty, then throwCasting error: Function constructor takes 1 argument
Assume that missing cases signify that that function doesn't exsist on that object.
UNDEFINED BEHAVIOR
- Takes 2 args,
- A function returning a boolean (as it is called multiple times)
- a function called after each time the boolean is found to be true.
- Also must return a boolean or nothing. If found to be false, but not undefined or null, loop stops.
This should allow for while, while-do, do-while and for behavior, as well as other awesome combos (like a while-do-while, do-while-do, or do-while-do-while).
part of the Bool
library
- Takes 2 args,
- a boolean
- a function called when boolean is true.
- Returns an object containing two methods:
elif
takes the same args as if and returns the same thing as if, but the function is only called if all previousif
or.elif
bools are false. In other words, it's only called when the state of theif
is false. (seeelse
below). Also returns the same thing asif
. same thing(s) asif
.else
takes a function, called only if all previous functions are false. Has no return.
If returns a function that resolves itself. Untill this is run, the if is not evaluated.
if(true,{
//code if true
});
if(1>0,{
//code if true
});
if(false,{
//code if true
}).else({
//code if false
});
if(99==93,{
//code if first true
}).elif(false,{
//code if 2nd true
}).else({
//code if 1 & 2 false
});
part of the Bool
library
NOTE: access restriction may need to be changed
- Takes 1-2 args
- A string that must refer to either a module name, a Unix-style url to a
file (extention not needed), or to a URL resorce that the OS can handle.
- NOTE: this file can also be a Redox style URL an IPFS style adress, or a git adress.
- An optional callback
- A string that must refer to either a module name, a Unix-style url to a
file (extention not needed), or to a URL resorce that the OS can handle.
- Returns the value
- When module is called, the module has no access to anything else and is gennerally treated as its own seperate, private program. Said module may also call import.
The imported module is logically wrapped around a function, the return of which is what becomes the return of [[import]].
NOTE: access restriction may need to be changed
- Takes 1-2 args
- A string with the same requirements as arg 0 of import
- An optional variable that is one of the following:
- An array of strings with the below description
- A string that exactly matches the name of the syntax conversion defined by
declareSyntax
. - A char (or single char str)
'*'
(sigifying all)
NOTE1: access restriction may need to be changed NOTE2: huge changes are going to happen here
Takes three args:
- A string representing the name of the conversion
- A regexp finding the match
- A function taking the match, returning the replacement.
A new regexp element.
These are some but not all of the resources that I have used thus far. (In no particular order)
- http://lucacardelli.name/Papers/TypeSystems.pdf
- Here's the IPFS link: /ipfs/QmcrFvSwxarj2r1HDMsBzcjt5SgtMcvCp8ByuFLk97WEov/TypeSystems.pdf
- https://thecodeboss.dev/2016/02/programming-concepts-type-introspection-and-reflection/
- https://www.info.ucl.ac.be/~pvr/VanRoyChapter.pdf
- Here's the IPFS link: /ipfs/QmcrFvSwxarj2r1HDMsBzcjt5SgtMcvCp8ByuFLk97WEov/VanRoyChapter.pdf
- https://thecodeboss.dev/2015/11/programming-concepts-static-vs-dynamic-type-checking/
- https://www.tutorialspoint.com/compiler_design/compiler_design_regular_expressions.htm
- https://en.wikipedia.org/wiki/Extensible_programming There are a lot of ideas here that I want. See the section titled "extensible compiler"
- http://wiki.c2.com/?ExtensibleProgrammingLanguage
- http://wiki.c2.com/?MetaProgramming
- https://en.wikipedia.org/wiki/Lambda_calculuss
- https://www.epaperpress.com/lexandyacc/index.html This is actually more than one link, and this is the TOC for them.
- http://www.paulgraham.com/langdes.html Great for knowing the "why" behind different different ideas.
- http://wiki.c2.com/?AutomatedCodeGeneration
- http://wiki.c2.com/?CompileTimeResolution
- https://wespiser.com/writings/wyas/01_introduction.html
- http://www.theenterprisearchitect.eu/blog/2013/02/14/designing-the-next-programming-language-understand-how-people-learn/
- https://tomassetti.me/antlr-mega-tutorial/
- https://tomassetti.me/resources-create-programming-languages/
- http://wiki.c2.com/?MetaProgramming
- http://wiki.c2.com/?StumblingBlocksForDomainSpecificLanguages
- http://wiki.c2.com/?LanguageOrientedProgramming
- http://www.jayconrod.com/posts/37/a-simple-interpreter-from-scratch-in-python-part-1
- https://ruslanspivak.com/lsbasi-part1/
- https://www.codeproject.com/articles/345888/how-to-write-a-simple-interpreter-in-javascript
- https://en.wikipedia.org/wiki/Haskell_(programming_language)
- http://www.stephendiehl.com/llvm/
- https://en.wikipedia.org/wiki/Parsec_(parser)
- A two parter on how lex and yacc work, respectivly
- http://www.onboard.jetbrains.com/articles/04/10/lop/ - From the maker of Intellij IDE and CEO of JetBrains! (concerning Language Oriented Programming)
- http://ropas.snu.ac.kr/~kwang/520/pierce_book.pdf
- http://wiki.c2.com/?LispMacro
- https://www.youtube.com/watch?v=lC5UWG5N8oY C++Now 2017: Ryan Newton "Haskell taketh away: limiting side effects for parallel programming"
- https://en.wikipedia.org/wiki/Backus%E2%80%93Naur_form
- https://www.youtube.com/watch?v=sTLkomM2P0o "Introduction to building a programming language" A talk about implimenting a subset of PHP in JavaScript
- https://cdsmith.wordpress.com/2011/01/09/an-old-article-i-wrote/ A great article on distinctions about different properties of type systems.