Creating a New Programming Language That Will Allow Anyone to Make Software

Geoff Cox
Geoff Cox
Jul 31, 2018 · 14 min read

I’ve spent the last 7 months working on a new programming language called MSON (pronounced Mason). Here is a nerdy post about why I did it, how it works and where I want to take it.

There are already a bazillion programming languages, why do we need another?

Language Principles

Declarative Syntax

Components

{
name: 'MyForm',
component: 'Form',
fields: [
{
name: 'name',
component: 'TextField',
label: 'Name',
required: true
},
{
name: 'email',
component: 'EmailField',
label: 'Email'
},
{
name: 'submit',
component: 'ButtonField',
label: 'Submit',
icon: 'CheckCircle'
}
]
}

Validators

{
name: 'MyForm',
component: 'Form',
fields: ...,
validators: [
{
where: {
'fields.email.value': 'nope@example.com'
},
error: {
field: 'email',
error: 'must not be {{fields.email.value}}'
}
}
]
}
where: {
'retypePassword.fields.value': {
$ne: '{{fields.password.value}}'
},
error: ...
}
{
name: 'MyForm',
component: 'Form',
fields: ...,
validators: ...,
listeners: [
{
event: 'submit',
actions: [
{
component: 'Set',
name: 'fields.email.value',
value: '{{fields.name.value}}@example.com'
}
]
}
]
}
listeners: [
{
event: 'submit',
actions: [
{
component: 'Set',
if: {
'fields.email': {
$or: [
{
value: null
},
{
value: ''
}
]
}
},
name: 'fields.email.value',
value: '{{fields.name.value}}@example.com'
}
]
}
]
listeners: [
{
event: 'submit',
actions: [
{
component: 'Action',
if: {
'fields.email': {
$or: [
{
value: null
},
{
value: ''
}
]
}
},
actions: [
{
component: 'Set',
name: 'fields.email.value',
value: '{{fields.name.value}}@example.com'
},
{
component: 'Set',
name: 'fields.name.value',
value: '{{fields.name.value}} Builder'
}
]
}
]
}
]
{
name: 'MyForm',
component: 'Form',
fields: ...,
validators: ...,
listeners: ...,
access: {
form: {
create: ['admin', 'manager'],
read: ['admin', 'employee'],
update: ['admin', 'owner', 'manager'],
archive: ['admin']
},
fields: {
name: {
create: ['admin'],
update: ['owner']
}
}
}
}
{
name: 'MyFormExtended',
component: 'MyForm',
fields: [
{
name: 'phone',
component: 'PhoneField',
label: 'Phone Number',
before: 'submit'
}
]
}
{
name: 'MyFormExtended',
component: 'MyForm',
fields: ...,
listeners: [
{
event: 'create',
actions: [
{
component: 'Set',
name: 'value',
value: {
name: 'Bob Builder',
email: 'bob@example.com',
phone: '(206)-123-4567'
}
},
{
component: 'Set',
name: 'fields.name.block',
value: false
},
{
component: 'Set',
name: 'fields.email.block',
value: false
},
{
component: 'Set',
name: 'fields.email.disabled',
value: true
}
]
}
]
}
{
name: 'MyTemplatedForm',
component: 'Form',
fields: [
'{{firstField}}',
{
name: 'secondField',
label: '{{secondFieldLabel}}',
component: 'EmailField'
}
]
}
{
name: 'MyFilledTemplatedForm',
component: 'MyTemplatedForm',
firstField: {
name: 'firstName',
component: 'TextField',
label: 'First Name'
},
secondFieldLabel: 'Email Address'
}
{
name: 'AddPhone',
component: 'Form',
componentToWrap: '{{baseForm}}',
fields: [
{
name: 'phone',
component: 'PhoneField',
label: 'Phone Number',
before: 'submit'
}
]
}
{
name: 'MyFormWithPhone',
component: 'AddPhone',
baseForm: {
component: 'MyForm'
}
}
{
name: 'MyAccount',
component: 'Form',
fields: [
{
name: 'firstName',
component: 'TextField',
label: 'First Name'
},
{
name: 'lastName',
component: 'TextField',
label: 'Last Name'
},
{
name: 'email',
component: 'EmailField',
label: 'Email'
}
]
}
{
name: 'MyAccountEditor',
component: 'RecordEditor',
baseForm: {
component: 'MyAccount'
},
label: 'Account'
}
{
name: 'MyAccountsList',
component: 'RecordList',
label: 'Accounts',
baseFormFactory: {
component: 'Factory',
product: {
component: 'MyAccount'
}
}
}
{
name: 'MyComponent',
component: 'Component',
schema: {
component: 'Form',
fields: [
{
name: 'hidden',
component: 'BooleanField',
help: 'Whether or not the component is hidden'
},
{
name: 'updatedAt',
component: 'DateTimeField',
required: true,
help: 'When the component was updated'
}
]
}
}
import compiler from 'mson/lib/compiler';
import Component from 'mson/lib/component';
import Form from 'mson/lib/form';
import { TextField } from 'mson/lib/fields';
import moment from 'moment';
class MyComponent extends Component {
_create(props) {
super._create(props);
this.set({
// Define a currentDay property
schema: new Form(
fields: [
new TextField({
name: 'currentDay'
})
]
),
// Default currentDay
currentDay: moment().format('dddd')
});
}
}
compiler.registerComponent('MyComponent', MyComponent);
import compiler from 'mson/lib/compiler';
import Action from 'mson/lib/actions/action';
import Form from 'mson/lib/form';
import { TextField } from 'mson/lib/fields';
class MyAction extends Action {
_create(props) {
super._create(props);
this.set({
schema: new Form(
fields: [
new TextField({
name: 'foo'
})
]
)
});
}
async act(props) {
const form = new FormData();
form.append('foo', this.get('foo'));
const account = props.component;
form.append('firstName', account.get('firstName');
form.append('lastName', account.get('lastName');
form.append('email', account.get('email');
return fetch({
'https://api.example.com',
{
method: 'POST',
body: form
}
})
}
}
compiler.registerComponent('MyAction', MyAction);
{
name: 'MyAccountExtended',
component: 'MyAccount',
listeners: [
{
event: 'submit',
actions: [
{
component: 'MyAction',
foo: 'bar'
}
]
}
]
}
import Form from 'mson/lib/form';
import { TextField, Email } from 'mson/lib/fields';
class MyAccount extends Form {
_create(props) {
super._create(props);
this.set({
fields: [
new TextField({
name: 'firstName',
label: 'First Name'
}),
new TextField({
name: 'lastName',
label: 'Last Name'
}),
new EmailField({
name: 'email',
label: 'Email'
})
]
})
}
}
import compiler from 'mson/lib/compiler';// Compile the MyAccount component
const MyAccount = compiler.compile({
component: 'MyAccount'
});
// Instantiate the JS class with a default value
const myAccount = new MyAccount({
// Default values
value: {
firstName: 'Bob'
}
});
// Set the remaining data
myAccount.set({
lastName: 'Builder',
email: 'invalid-email@'
});
// Make sure the values are valid
myAccount.validate();
if (myAccount.hasErr()) {
console.log(myAccount.getErrs());
}
{
component: 'Form',
fields: [
{
name: 'email',
component: 'EmailField',
label: 'Email'
},
{
name: 'message',
component: 'TextField',
label: 'Message'
},
{
name: 'Submit',
component: 'ButtonField',
label: 'Submit'
}
],
listeners: [
{
event: 'submit',
actions: [
{
// Send an email on the back end
component: 'Email',
layer: 'backEnd',
from: '{{fields.email.value}}',
to: 'noreply@example.com',
subject: 'My message',
body: '{{fields.message.value}}',
// Detach so that user doesn't have to wait for email
// to send
detach: true
},
{
// Display a message to the user on the front end
component: 'Snackbar',
layer: 'frontEnd',
message: 'Thanks for the message'
}
]
}
]
}
{
name: 'MyUser',
component: 'Form',
fields: [
{
name: 'name',
component: 'TextField',
label: 'Name'
},
{
name: 'email',
component: 'EmailField',
label: 'Email'
},
{
name: 'password',
component: 'PasswordField',
label: 'Password',
hidden: true,
in: false,
out: false
}
]
}
{
name: 'EditPasswordForm',
component: 'MyUser',
listeners: [
{
event: 'create',
actions: [
{
// Hide all fields
component: 'Set',
name: 'hidden',
value: true
},
{
// Show password field
component: 'Set',
name: 'fields.password.hidden',
value: false
},
{
// Allow user to write password to the back end
component: 'Set',
name: 'fields.password.out',
value: true
}
]
}
]
}

Next Steps

About the Author

HackerNoon.com

#BlackLivesMatter