Jome
Jome tries to be an unopiniated programming language. You code using your own style and use a linter in other to share standardized code with other people.
You should use a specialized editor (WIP) in order to fully use all it's features such as code evaluation (like Jupyter Notebook) and data editing (like spreadsheet with types inside the editor).
It has nice features like a base library and macros.
For the near future, it only compiles to JavaScript.
Status
Jome is in early development stage. It is not usable yet.
The compiler does not handle all the features described here. Tests are lacking and there is a lot of bugs.
Code Sample
#*
# Torque Calculator Example
*#
with
Number force = ? N* // Newtons or equivalent
Number distance = ? m* // meters or equivalent
end
# Torque is the result of a force multiplied by a distance from a pivot point.
// We use a jome tag because it's a script that can be run
// The unit checker can infer that this block returns a value
// with N*m or equivalent as a unit and shows it.
return <jome>force * distance</jome> // the last value from a Jome tag is returned
Result inside the editor:
Torque Calculator Example
Torque is the result of a force multiplied by a distance from a pivot point.
return force * distance
Result inside the shell:
jome torqueCalculator.jome --force=10 --distance="2 m"
# => 20 N·m
Usage inside another file:
import calculateTorque from './torqueCalculator.jome'
let torque = calculateTorque force: 20 lbs, distance: 1 in
Features
Here is a list of the features of Jome.
1. Base library
Every project can choose a base library. This library should contain common utility functions and constants.
// Example using lodash as a base library
<?lib 'lodash' ?>
// Then you get access to all the named exports by prepending an hashtag symbol before.
#partition([1, 2, 3, 4], n => n % 2)
// → [[1, 3], [2, 4]]
// You can also use the hashtag operator (.#) to put the first operand before instead of after.
{ 'a': 1 }.#defaults({ 'a': 3, 'b': 2 })
// → { 'a': 1, 'b': 2 }
Read more on Base library (TODO Link)
2. Flexible syntax
You can code using the syntax you prefer. The project should specify a linter so the code is converted to a standard when you save.
Also, the idea is that when you open a page, the editor should show you the code in the syntax that you prefer.
if val == 20: doSomething()
if (val == 20) { doSomething() }
if (val == 20) doSomething() end
calcSomething 1, 2 // You can omit parentheses for a function call
Read more on Flexible syntax (TODO Link)
3. Flexible typing system
Like the rest of Jome, the typing system is flexible. You can omit them, you can use hard typing or you can use duct typing.
let addInts = (x, y) => x + y
let addInts = (int x, int y) => x + y
int addInts = (int x, int y) => x + y
let addInts = (x : int, y : int) => x + y
let addInts : int = (x : int, y : int) => x + y
4. with blocks
You can pass parameters to a file using a with block. This allows you to treat a file as a function. You can import it from another file. And you can call it directly from the CLI.
with {port = 3000} // default port is 3000, but allow to run the file with a different port number
6. Unit system
Unit are a way to be more specific when using numbers. They are only available at compile time.
You can specify the unit after a number or use the middle dot (·) to apply a unit to a variable. The editor should make this symbol easyily accessible. You can also simply multiply by 1 of the unit.
let width = 5
let force = 10 N // Newtons
let distance = width·m // meters // same as width*1m
let torque = force * distance
jome.print(torque) // jome.print is a macro that prints the unit based on the context
// → 50 N·m
Units have limitations. They are a compile time feature.
let force = unitSystem === 'metric' ? 1 lb : 10 N
jome.print(force)
// → 10 // The unit is not printed because it can't be inferred.
You can specify that a function takes a value in a specific unit. When called, it can be automatically converted if the given unit is an equivalent.
def sleep(time = ? ms)
/* ... */
end
sleep(2 s) // compiled to: sleep(2000)
You can get the unit of a variable as a string using the unitof operator. Note: You must use a macro to use this on a parameter.
let unit = unitof someVar
8. sourceof
The sourceof keyword tells the compiler to extract the source code of the value of a given variable as a string.
def debug(value)
console.log(sourceof(value), ': ', value)
end
let someVar = 3
debug(someVar) // compiled as debug(someVar, "someVar")
// => someVar: 3
It should work magically inside functions. Every function using the sourceof keyword for a parameter would get an extra hidden parameter.
9. unitof
The unitof keyword tells the compiler to extract the unit of the value of a given variable as a string.
macro calc(value)
console.log(sourceof(value), ' = ', value, ' ', unitof(value))
end
calc(1 + 1 N) // compiled as calc(1+1, "1 + 1 N", "N")
// => 1 + 1 N = 2 N
It should work magically inside functions. Every function using the unitof keyword for a parameter would get an extra hidden parameter.
11. User configs## 10. Feature proposal - Jome API
In order to make code that can compile in many programming language, there would be an API available under the Jome object.
jome.print("Hello world!") // compiles to console.log in js, printf in c, puts in ruby, etc.
It's an idea. It is not implemented yet. Only javascript as a base language is supported for now.
print: console.log as a macro to print unit debug: console.log as a macro to print code and unit
Wait until implementing this because this would be final and would have to be backward compatible moving onward.
And maybe do polls. Like for printing to console: jome.print vs jome.log vs jome.cout vs jome.console.log vs ...
Some configs are for the projects. For example the base library.
Some configs are specific to the user. There should be a file somewhere (offer cloud base storage for this config?) that define your preferences.
For example, setting if you prefer tabs or spaces. How many spaces is equivalent to a tab...
Then the editor should show you how you like it.
You can already customize editors to do this.
But Jome goes further because it is more customizable. You specify what syntax you prefer for code. The editor should show you code in the syntax you prefer.
11. Save process
TODO: Do an image to show this.
There are 3 things.
Notebook view: This is what the user sees.
User code: This is the code in the format that the user prefers.
Project code: This is how the code is saved to file, as is specified by the linter configs.
When you open a file in the editor, it should read the project code.
Then if the user is in view mode, it should show the notebook view.
If the user is in edit mode, it should show the user code.
NOTE: The big issue I see is that the translation from user code to project code must work 100% of the time, otherwise there could be reallllllly annoying bugs where the code looks fine, but it's not translated properly and it bugs.
11. Operators
Operators are a user specific config. You define what you prefer.
For example, you specify if you prefer ^ or ** for exponential.
<?op-exp ^ ?>
11. Processing instruction
Jome uses XML processing instructions to define the language. They start with <? and end with ?>.
Processing instructions are in effect under where it is defined and in config.jome.
Work in progress.
The syntax may vary depending on the processing instruction. Refer to the specific one used.
Processing instructions available:
- model: Define a data structure. Ex:
- file-loader: Define how to load a file with a given extension.
- unit: Define a new unit
- tag: Define a tag that is not a model
- renderer: Maybe? To define how to render a tag to html for the editor?
- lib: Specify the base library for the project
- config-...: Specify a config (or set-...) (ex: )
12. Tags
You can define tags like <color></color> using the processing instruction <?tag ... ?>
<?tag color type="color" ?>
Parameters:
- type: color, number, text, ... (pretty much all html input types)
12. Models
A model defines a data strcture. It allows to use xml, validation, serializing, database management...
You can define your own models which can then be created using xml tags or programmatycally.
You can create a class with the same name (case insensitive?) than the model to complement it.
<?model Recipe name: "string"
<attr name="servings" type="string" optional />
<has_many name="ingredients" model="ing" optional>
<has_many name="steps" model="step" optional>
<component model="ing">
<attr name="qty" type="string" />
<attr name="name" type="string" />
</component>
<component model="step">
<content name="text" type="string" />
</component>
?>
A model creates a static function new for the class of the same name.
Or is this confusing with the constructor which will be called with new keyword?
Yeahh... don't do this. Override the constructor. This way the validations are always called.
If the user defines a constructor inside the class, then simply merge them together? Wait
now it's not clear how to call it then...?
You can define custom schemas for xml tags.
schema Recipe { def toHTML end }
What does defining a schema should do?
It should create a class that allows you to handle it programmatycally.
<recipe
name="Biscuits aux brisures de chocolat"
>
<ingredients>
<ing><qty>1 t</qty><item>farine</item></ing>
<ing><qty>1 t</qty><item>beurre</item></ing>
</ingredients>
<steps>
<step>Mélanger @1 avec @2</step>
</steps>
</recipe>
Editor
Jome is meant to be used with a specialized editor in order to fully use it's features. Here are the main features that should be given by an editor.
1. Notebook view
There are regular comments starting with // or delimited by /* and */.
But there are also comments starting with # (with space) or delimited by #* and *#.
These use markdown and should be showned rendered as a notebook like jupyter.
#*
# My awesome application
It uses [https://www.sqlite.org/index.html](SQLite) as a databse.
*#
2. Notebook execution
The editor should allow you to execute chunks of code and view the result.
The <jome> tag is used for this purpose and tells the editor to show the result of the code inside the tag.
let x = 10
let y = 2
let z = <jome>10 ** 2</jome>
Data cells
There is two kinds of data. There is runtime data. And there is static data.
Runtime data is data given using the with keyword. When you reload this page, you loose this.
Static data is data directly inserted into the code. When you save you modify the source code.
Jome introducte the idea of data cells in a notebook.
The idea is that you should be able to enter data in a spreadsheet like format in the notebook.
TODO: Explain that tags are data cells, and that right now I am simply abusing the markdown cells
How to support =A1+B2 ?
// A table like this should be editable as a spreadsheet in the editor
< table >
< tr >
< th >Name</ th >
< th >Age</ th >
< th >City</ th >
</ tr >
< tr >
< td >John Doe</ td >
< td >25</ td >
< td >Montréal</ td >
</ tr >
< tr >
< td >Jane Smith</ td >
< td >30</ td >
< td >Québec</ td >
</ tr >
< / table >
Collapsed code cells
There should also be collapsed by default code cells. For example for imports. If you click on it, you should see it. But you could also that it is collapsed by default.
But I want to be able to search for it though... CTRL+F should find text hidden inside the collapsed cell. Not sure if that is possible in the browser...
Ah yes, maybe simply make is small and scrollable, but when it gains focus, it becomes bigger! This should work with CTRL+F!
You can enter data using to the file using tags or you can enter temporary data using a with block. See below.
3. Code data
You can write code data using xml. The editor should make it easy to edit this data.
For example, a <color> tag should show a color picker. A spreadsheet tag should show a spreadsheet table.
Feature proposals
Feature ideas
1. Feature proposal - Custom base language (flavor?)
Only javascript is supported for now.
Jome is compiled into the base language choosen.
Jome operators are exactly the same as the base language.
It also makes all the globals available from the base language available in Jome.
with flavor js // you can omit this, this is the default
console.log("Hello") // console is available because of javascript
let y = 10 ** 2 // ** is the exponentiation operator like javascript
If you want total control even let's say on the operators, you could eventually design a custom language.
2. Feature proposal - Jome API
In order to make code that can compile in many programming language, there would be an API available under the Jome object.
jome.print("Hello world!") // compiles to console.log in js, printf in c, puts in ruby, etc.
It's an idea. It is not implemented yet. Only javascript as a base language is supported for now.
print: console.log as a macro to print unit debug: console.log as a macro to print code and unit
Wait until implementing this because this would be final and would have to be backward compatible moving onward.
And maybe do polls. Like for printing to console: jome.print vs jome.log vs jome.cout vs jome.console.log vs ...
13. Feature proposal - Function overloading based on type
I'd like to be able to overload a function based on type.
For example:
def add(Vector3 v1, Vector3 v2)
return v1.add(v2)
end
def add(o1, o2)
return o1 + o2
end
add(Vector3(0,0,0), Vector3(1,1,1)) // uses the first because type matches
add(1, 2) // uses the second, the default one
14. Feature proposal - Operator overloading for classes
I'd like to be able to overload an operator for a class.
For example:
class Vector3
def add(v2)
return Vector3(@x + v2.x, @y + v2.y, @z + v2.z)
end
end
let v3 = Vector3(0,0,0) + Vector3(1,1,1)
This would mostly be useful to people who enable hardtyping. Because if you forget to specify the type in a function for example, this won't be called.
Feature proposal - Class templates
I'd like class templates like in c++ I think. Check how other languages are handling that though.
Trash
Jome is a language that compiles to JavaScript. It has goodies like CoffeeScript and underscore.js, permissive syntax similar to either javascript or ruby and it has some original features. One day, it will have a node structure like in Godot, types like Typescript, and reactivity like svelte.
Customizable builtins - Jome comes with a lot of builtins which you can map to keywords you want. You can also define your own.
Reactivity - TODO
Node structure like Godot - TODO
-
Notebook comments - You can add documentation comments using markdown to create a notebook like jupyter.
-
Inline data - TODO: You can do advamced stuff with inline data using tags (preprocessing, ...)
-
Flexible syntax - You can code using the style you prefer and use a linter to share code in a standardized way.
-
Flexible typing - You can use static typing for robustness and usability or omit them for development speed and simplicity.
-
Custom base library - Choose the base library for your project to reuse common functionalities.
-
A unit system - You can add units to numbers. Smart conversions are done at compile time to ensure you use the proper units.
-
Custom base language - Choose the language to jome compiles to and inherits operators and globals (Only javascript supported for now)
-
Macros - Add extra parameters given the context of the function call.