Git Product home page Git Product logo

liblucy's People

Contributors

matthewp 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  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  avatar  avatar  avatar

liblucy's Issues

Nested states without nested machines

I'm thinking that having nested states by nesting a machine is kind of strange. It's like a machine but also is completely tied to the outer. Does it make sense to just have states directly inside of states instead?

Add node/browser lib for Lucy

import { parseToJson } from '@lucylang/node';

const machine = parseToJson(
`
// Lucy file in here
`
)

Many use-cases for this - JS runtime, browser-based tooling, all sorts of cool stuff.

Bug with `delay` token

Problem

Currently the delay token compiles to the delay property in the XState configuration result.

Expected

delay should be compiled to after.

Sample

Input:

initial state green {
  delay(1s) => yellow
}

state yellow {
  delay(500) => red
}

state red {
  delay(calcLightDelay) => green
}

Output:

import { Machine } from 'xstate';

export default Machine({
  initial: 'green',
  states: {
    green: {
      after: {
        1000: 'yellow'
      }
    },
    yellow: {
      after: {
        500: 'red'
      }
    },
    red: {
      after: {
        calcLightDelay: 'green'
      }
    }
  }
}, {
  delays: {
    calcLightDelay: 3000
  }
});

[IDEA] XState JSON to Lucy?

Hi!! Thanks for you work!! It's been fun playing with Lucy ๐Ÿ˜Š

I was thinking would it be possible to generate Lucy files from XState JSON definitions? Not sure if it would be super complex or is something simple.

I thought about it as I was replicating my XState machines in Lucy manually :)

Thanks!

Invoking "use reference" is incorrectly referenced in services property

I'm trying to follow the example from Lucy's website for using an "use reference" in invoke statement. I'm quite new to state machines in general so my terminology and expectations might be incorrect here - feel free to correct me.

Input:

use './utils' { getUsers }

state idle {
  invoke(:getUsers) {
    done => assign(users)
  }
}

Output with @lucy/[email protected]:

01 | import { createMachine, assign } from 'xstate';
02 | import { getUsers } from './utils';
03 | 
04 | export default function({ context = {}, services } = {}) {
05 |   return createMachine({
06 |     context,
07 |     states: {
08 |       idle: {
09 |         invoke: {
10 |           src: 'getUsers',
11 |           onDone: {
12 |             actions: [
13 |               assign({
14 |                 users: (context, event) => event.data
15 |               })
16 |             ]
17 |           }
18 |         }
19 |       }
20 |     }
21 |   }, {
22 |     services: {
23 |       getUsers: services.getUsers
24 |     }
25 |   });
26 | }

Note that on the line 2 the imported getUsers is an unused variable. It is not used on line 23.

I would expected the output to be:

22 |     services: {
23 |       getUsers,
24 |     }

or maybe even

22 |     services: {
23 |       getUsers,
24 |       ...services,
25 |     }
Here is my custom webpack loader which applies a temporary work-around
module.exports = function(content) {
    const callback = this.async();

    import('@lucy/liblucy')
        .then(({ ready, compileXstate }) => {
            ready
                .then(() => {
                    const { js } = compileXstate(content, this.resourcePath);

                    callback(undefined, applyFixes(js));
                })
                .catch(e => {
                    callback(
                        `Lucy loader failed to compileXstate: ${e.message}`
                    );
                });
        })
        .catch(callback);
};

function applyFixes(input) {
    const output = input.replace(/services\./gi, '');

    console.log('input', input);
    console.log('output', output);

    return output;
}

Assign with no transition has `"ssign"` or `""` as target

Hey,
Noticed that if you try to make a transition containing only an assign action, it adds a "ssign" target if no other state is defined, or "" if another state is defined (whereas I would expect no target in such a case)

state initial {
  TEST => assign(someValue)
}

The resulting code is

import { createMachine, assign } from 'xstate';

export default createMachine({
  states: {
    initial: {
      on: {
        TEST: {
          target: 'ssign',
          actions: [
            assign({
              someValue: (context, event) => event.data
            })
          ]
        }
      }
    }
  }
});

And when doing the following:

state initial {
  TEST => assign(someValue)
}

state other {}

The resulting code is

import { createMachine, assign } from 'xstate';

export default createMachine({
  states: {
    initial: {
      on: {
        TEST: {
          target: '',
          actions: [
            assign({
              someValue: (context, event) => event.data
            })
          ]
        }
      }
    },
    other: {

    }
  }
});

I'm aware that Lucy is in alpha and issues are to be expected, just wanted to give you a heads up :)

Good luck!

Actions in nested machines

I think that i found a bug in lucy 0.3.4

use './utils.js' {assignDays}

machine testMachine {
  action assignDays = assignDays

  initial state test {}
}

compiles to

import { createMachine } from 'xstate';
import { assignDays } from './utils.js';

export function createTestMachine({ context = {} } = {}) {
  return createMachine({
    initial: 'test',
    context,
    states: {
      test: {

      }
    }
  }, {
    actions: {
      assignDays: assignDays
    }
  });
}

which is ok, but

use './utils.js' {assignDays}

machine testMachine {
  action assignDays = assignDays

  initial state test {
    machine nested {
    }
  }
}

compiles to

import { createMachine } from 'xstate';
import { assignDays } from './utils.js';

export function createTestMachine({ context = {} } = {}) {
  return createMachine({
    initial: 'test',
    context,
    states: {
      test: {
        context
      }
    }
  });
}

where actions dissapeared

Compile hangs if too many repeated event definitions

I believe I've isolated this down. In the tableau state there are multiple repeated up and down transitions with different given guards. If you delete any two of those event transitions it'll correctly compile. With three or more present it'll hang the compiler.

machine highlighted {

  guard isUnderStock = :isUnderStock
  guard isUnderWaste = :isUnderWaste
  guard isUnderFoundation = :isUnderFoundation

  initial state stock {
    up => tableau
    down => tableau
    left => foundation
    right => waste
  }

  state foundation {
    up => tableau
    down => tableau

    left => guard(:isStartOfFoundation) => waste
    left => foundation

    right => guard(:isEndOfFoundation) => stock
    right => foundation
  }

  state waste {
    up => tableau
    down => tableau
    left => stock
    right => foundation
  }

  state tableau {
    up => isUnderStock => stock
    up => isUnderWaste => waste
    up => isUnderFoundation => foundation
    up => tableau

    down => isUnderStock => stock
    down => isUnderWaste => waste
    down => isUnderFoundation => foundation
    down => tableau

    left => tableau
    right => tableau
  }
}

Guards for immediate transitions

guard isValid = isValid

initial state firstState {
  => isValid => secondState
}

state secondState {

}

This appears not to print anything into the cond of the always

Incorrect indentation when a reference follows an inline assign

use './util' { logger }

action log = logger

state idle {
  go => assign(prop) => log
}

Compiles to:

import { createMachine, assign } from 'xstate';
import { logger } from './util';

export default createMachine({
  states: {
    idle: {
      on: {
        go: {
          actions: [
            assign({
              prop: (context, event) => event.data
            }), 'log'
          ]
        }
      }
    }
  }
}, {
  actions: {
    log: logger
  }
});

'log' should be on a newline

Why not javascript?

Hi there, this project looks great with super exciting potential :D

I came straight to the github, keen to see juicy implementation details, only to find it written in C, a language that I am generally not good at and find hard to read (and not buildable on windows?) :( Nothing wrong with C of course... I am just curious though, why not typescript / PEGjs for the core? Is javascript really too slow for this?

Allow for multiple guards in transitions

initial state firstState {
  go => guard(isAllowed) => secondState
}

state secondState {}

state notAllowedState {}

Given a state machine like the one above, how would one default to going to the notAllowedState if isAllowed evaluated to false?

Named actions/guards get shared with sibling machines

use './util' { logger }

machine one {
  action log = logger

  state idle {
    go => log
  }
}

machine two {}

Compiles to:

import { createMachine } from 'xstate';
import { logger } from './util';

export const one = createMachine({
  states: {
    idle: {
      on: {
        go: {
          actions: ['log']
        }
      }
    }
  }
}, {
  actions: {
    log: logger
  }
});

export const two = createMachine({

}, {
  actions: {
    log: logger
  }
});

Here two should not have the logger.

Parallel states

Probably through a modifier like with final/initial.

parallel machine File {

}

Not an issue: compilation to Robot and other machine libraries

Congrats on the new DSL! It is indeed a significant improvement on the experience of writing large-enough state machines (e.g., using state machines where they do make sense). I have two questions:

  • why not compile to Robot (say, a "strict mode" version of the language that does not include actors)? It still makes sense to have the small size
  • how easy would it be to compile to Kingly -- e.g., another state machine library? Kingly also has a compiler to vanilla JS (zero dependencies) but from a visual language (saved as .graphml file). I am interested to see how this could be used as an equivalent textual language.

Got to look at your code anyways to see how you did it but thought I'll stop by and ask.

[edit]: Ok, I had a quick look and it seems like I should be able to reuse your parser. I should just have to rewrite the traversal of the parsed tree (ParseResult). Does that make sense to you? BTW that is terrificly well-written C code. I haven't read C in a decade, and that went like a charm even without comments :-)

Runtime

Is there a runtime for this as well?

Similar to how in graphql you can create documents by using the 'gql' function, would it be possible to create state machines in the same way?

I saw a twitter post too with this exact approach.

https://twitter.com/n_moore/status/1385986489797029894?s=21

I look forward to this project's growth ๐Ÿ˜ƒ

Allow for unimplemented actions/services/guards

Sometimes, actions/services/guards are best implemented not in the initial definition of the machine. Sometimes, it's best to leave them unimplemented until you use the machine in your frontend/backend code.

This means that Lucy would need to compile action definitions that aren't imported via use.

Error installing on Mac with zsh - command not found: lc

I'm really interested in trying Lucy! Thanks for your work.

Problem

I tried to do what the install page says on my terminal https://lucylang.org/install/:

curl -sSf https://lucylang.org/install.sh | bash

It went ok!

Then did

lc --help

But I get

zsh: command not found: lc

Checked my .zshrc config and it automatically added a

export PATH="/Users/santicros/.lucy/bin:$PATH"

Solution

I found that removing the final $PATH made it work, so:

export PATH="/Users/santicros/.lucy/bin"

:D

Typescript Codegen Support

Opening this issue to spawn a discussion about type-safety. Lucy offers a nice opportunity to increase TS type safety by statically analysing the machine. This is similar to, but much more reliable than, xstate-codegen. xstate-codegen pulls out machines from JS/TS, which is fraught with issues. Lucy could statically analyse files, free of side effects, and create 100% perfect types every time.

What do perfect types look like?

  1. All actions/guards/services know what events caused them to fire.
  2. state.matches can be made type safe.

Because Lucy compiles to out.js files, an accompanying .d.ts file would be appropriate. Users could also pass it generics, such as TEvent and TContext, similar to xstate-codegen.

Interested to hear your thoughts.

Allow comments

Comments using:

// comment

...appear not to be possible. This would be great, and also support the examples in the docs.

Target a nested state with an event

Given a machine that looks like this:

initial state idle {
  fetch => fetching

  machine idling {
    initial state noError {
      @entry => action(:clearErrorMessage)
    }

    state errored {}
  }
}

state fetching {
  reportError => idle.errored
}

I would like to target a nested state. Something like reportError => idle.errored.

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.