diff --git a/src/actions/actionTypes.ts b/src/actions/actionTypes.ts index 735b1a65c0..536d1fdee9 100644 --- a/src/actions/actionTypes.ts +++ b/src/actions/actionTypes.ts @@ -13,8 +13,6 @@ export const CLEAR_REPL_INPUT = 'CLEAR_REPL_INPUT' export const CLEAR_REPL_OUTPUT = 'CLEAR_REPL_OUTPUT' export const CLEAR_CONTEXT = 'CLEAR_CONTEXT' export const SEND_REPL_INPUT_TO_OUTPUT = 'SEND_REPL_INPUT_TO_OUTPUT' -export const CHAPTER_SELECT = 'CHAPTER_SELECT' -export const CHANGE_CHAPTER = 'CHANGE_CHAPTER' /** Interpreter */ export const HANDLE_CONSOLE_LOG = 'HANDLE_CONSOLE_LOG' diff --git a/src/actions/playground.ts b/src/actions/playground.ts index 39b772f22c..c900fe6437 100644 --- a/src/actions/playground.ts +++ b/src/actions/playground.ts @@ -1,4 +1,3 @@ -import { ChangeEvent } from 'react' import { ActionCreator } from 'redux' import * as actionTypes from './actionTypes' @@ -20,18 +19,6 @@ export const sendReplInputToOutput: ActionCreator = (newOut } }) -export const chapterSelect: ActionCreator = ( - e: ChangeEvent -) => ({ - type: actionTypes.CHAPTER_SELECT, - payload: e.currentTarget.value -}) - -export const changeChapter: ActionCreator = (newChapter: number) => ({ - type: actionTypes.CHANGE_CHAPTER, - payload: newChapter -}) - export const evalEditor = () => ({ type: actionTypes.EVAL_EDITOR }) diff --git a/src/components/IDE/Control.tsx b/src/components/IDE/Control.tsx index c366f58028..39523903ca 100644 --- a/src/components/IDE/Control.tsx +++ b/src/components/IDE/Control.tsx @@ -1,7 +1,6 @@ -import { Button, IconName, Intent } from '@blueprintjs/core' import * as React from 'react' -import { sourceChapters } from '../../reducers/states' +import { Button, IconName, Intent } from '@blueprintjs/core' /** * @property handleEvalEditor - A callback function for evaluation @@ -11,40 +10,26 @@ export interface IControlProps { handleEvalEditor: () => void handleEvalRepl: () => void handleClearReplOutput: () => void - handleChapterSelect: (e: React.ChangeEvent) => void } -const genericButton = ( - label: string, - icon: IconName, - handleClick = () => {}, - intent = Intent.NONE, - notMinimal = false -) => ( - -) - -const chapterSelect = (handleSelect = (e: React.ChangeEvent) => {}) => ( -
- -
-) - class Control extends React.Component { public render() { + const genericButton = ( + label: string, + icon: IconName, + handleClick = () => {}, + intent = Intent.NONE, + notMinimal = false + ) => ( + + ) const runButton = genericButton('Run', 'play', this.props.handleEvalEditor) const evalButton = genericButton('Eval', 'play', this.props.handleEvalRepl) const clearButton = genericButton('Clear', 'remove', this.props.handleClearReplOutput) @@ -53,9 +38,8 @@ class Control extends React.Component {
{runButton}
- {chapterSelect(this.props.handleChapterSelect)} -
{evalButton}
-
{clearButton}
+
{evalButton}
+
{clearButton}
diff --git a/src/components/IDE/__tests__/Control.tsx b/src/components/IDE/__tests__/Control.tsx index ada0fe6e1a..2a2c8646b3 100644 --- a/src/components/IDE/__tests__/Control.tsx +++ b/src/components/IDE/__tests__/Control.tsx @@ -8,8 +8,7 @@ test('Control renders correctly', () => { const props: IControlProps = { handleEvalEditor: () => {}, handleEvalRepl: () => {}, - handleClearReplOutput: () => {}, - handleChapterSelect: (e: React.ChangeEvent) => {} + handleClearReplOutput: () => {} } const app = const tree = shallow(app) diff --git a/src/components/IDE/__tests__/__snapshots__/Control.tsx.snap b/src/components/IDE/__tests__/__snapshots__/Control.tsx.snap index 1dc888996b..162ba7418a 100644 --- a/src/components/IDE/__tests__/__snapshots__/Control.tsx.snap +++ b/src/components/IDE/__tests__/__snapshots__/Control.tsx.snap @@ -9,22 +9,12 @@ exports[`Control renders correctly 1`] = `
-
- -
-
+
Eval
-
+
Clear diff --git a/src/containers/IDE/ControlContainer.ts b/src/containers/IDE/ControlContainer.ts index d76e3a9d57..bf0102f302 100644 --- a/src/containers/IDE/ControlContainer.ts +++ b/src/containers/IDE/ControlContainer.ts @@ -1,14 +1,13 @@ import { connect, MapDispatchToProps, MapStateToProps } from 'react-redux' import { bindActionCreators, Dispatch } from 'redux' -import { chapterSelect, clearReplOutput, evalEditor, evalRepl } from '../../actions/playground' +import { clearReplOutput, evalEditor, evalRepl } from '../../actions/playground' import Control, { IControlProps } from '../../components/IDE/Control' import { IState } from '../../reducers/states' type DispatchProps = Pick & Pick & - Pick & - Pick + Pick /** No-op mapStateToProps */ const mapStateToProps: MapStateToProps<{}, {}, IState> = state => ({}) @@ -21,8 +20,7 @@ const mapDispatchToProps: MapDispatchToProps = (dispatch: Dis { handleEvalEditor: evalEditor, handleEvalRepl: evalRepl, - handleClearReplOutput: clearReplOutput, - handleChapterSelect: chapterSelect + handleClearReplOutput: clearReplOutput }, dispatch ) diff --git a/src/mocks/context.ts b/src/mocks/context.ts index ded2dfc7df..12ecd4c6f7 100644 --- a/src/mocks/context.ts +++ b/src/mocks/context.ts @@ -1,6 +1,6 @@ import { createContext } from '../slang' import { Context } from '../slang/types' -export function mockContext(chapter = 1): Context { - return createContext(chapter) +export function mockContext(): Context { + return createContext() } diff --git a/src/reducers/playground.ts b/src/reducers/playground.ts index 9829faa415..c42e4a45ab 100644 --- a/src/reducers/playground.ts +++ b/src/reducers/playground.ts @@ -1,6 +1,5 @@ import { Reducer } from 'redux' import { - CHANGE_CHAPTER, CLEAR_CONTEXT, CLEAR_REPL_INPUT, CLEAR_REPL_OUTPUT, @@ -42,12 +41,7 @@ export const reducer: Reducer = (state = defaultPlayground, ac case CLEAR_CONTEXT: return { ...state, - context: createContext(state.sourceChapter) - } - case CHANGE_CHAPTER: - return { - ...state, - sourceChapter: action.payload + context: createContext() } case HANDLE_CONSOLE_LOG: /* Possible cases: diff --git a/src/reducers/states.ts b/src/reducers/states.ts index 843c0f2048..435cf2f790 100644 --- a/src/reducers/states.ts +++ b/src/reducers/states.ts @@ -11,11 +11,7 @@ export interface IApplicationState { readonly environment: ApplicationEnvironment } -export const sourceChapters = [1, 2] -const latestSourceChapter = sourceChapters.slice(-1)[0] - export interface IPlaygroundState { - readonly sourceChapter: number readonly editorValue: string readonly replValue: string readonly context: Context @@ -91,9 +87,8 @@ export const defaultApplication: IApplicationState = { } export const defaultPlayground: IPlaygroundState = { - sourceChapter: latestSourceChapter, editorValue: '', replValue: '', - context: createContext(latestSourceChapter), + context: createContext(), output: [] } diff --git a/src/sagas/index.ts b/src/sagas/index.ts index 77077007e4..de6a26988b 100644 --- a/src/sagas/index.ts +++ b/src/sagas/index.ts @@ -6,7 +6,6 @@ import { Context, interrupt, runInContext } from '../slang' import * as actions from '../actions' import * as actionTypes from '../actions/actionTypes' -import { showSuccessMessage } from '../notification' function* evalCode(code: string, context: Context) { const { result, interrupted } = yield race({ @@ -45,20 +44,6 @@ function* interpreterSaga(): SagaIterator { yield put(actions.sendReplInputToOutput(code)) yield* evalCode(code, context) }) - - yield takeEvery(actionTypes.CHAPTER_SELECT, function*(action) { - const newChapter = parseInt((action as actionTypes.IAction).payload, 10) - const oldChapter = yield select((state: IState) => state.playground.sourceChapter) - if (newChapter !== oldChapter) { - yield put(actions.changeChapter(newChapter)) - yield put(actions.handleInterruptExecution()) - yield put(actions.clearContext()) - yield put(actions.clearReplOutput()) - yield call(showSuccessMessage, `Switched to Source \xa7${newChapter}`) - } else { - yield undefined - } - }) } function* mainSaga() { diff --git a/src/slang/createContext.ts b/src/slang/createContext.ts index d958b515a9..b3191554cd 100644 --- a/src/slang/createContext.ts +++ b/src/slang/createContext.ts @@ -17,8 +17,8 @@ const createEmptyRuntime = () => ({ nodes: [] }) -export const createEmptyContext = (chapter: number): Context => ({ - chapter, +export const createEmptyContext = (week: number): Context => ({ + week, errors: [], cfg: createEmptyCFG(), runtime: createEmptyRuntime() @@ -56,7 +56,7 @@ export const importExternals = (context: Context, externals: string[]) => { export const importBuiltins = (context: Context) => { ensureGlobalEnvironmentExist(context) - if (context.chapter >= 1) { + if (context.week >= 3) { defineSymbol(context, 'runtime', misc.runtime) defineSymbol(context, 'display', misc.display) defineSymbol(context, 'error', misc.error_message) @@ -79,15 +79,22 @@ export const importBuiltins = (context: Context) => { } } - if (context.chapter >= 2) { - // List library + if (context.week >= 4) { + defineSymbol(context, 'math_log', Math.log) + defineSymbol(context, 'math_exp', Math.exp) + defineSymbol(context, 'alert', alert) + defineSymbol(context, 'math_floor', Math.floor) + defineSymbol(context, 'timed', misc.timed) + } + + if (context.week >= 5) { + defineSymbol(context, 'list', list.list) defineSymbol(context, 'pair', list.pair) defineSymbol(context, 'is_pair', list.is_pair) + defineSymbol(context, 'is_list', list.is_list) + defineSymbol(context, 'is_empty_list', list.is_empty_list) defineSymbol(context, 'head', list.head) defineSymbol(context, 'tail', list.tail) - defineSymbol(context, 'is_empty_list', list.is_empty_list) - defineSymbol(context, 'is_list', list.is_list) - defineSymbol(context, 'list', list.list) defineSymbol(context, 'length', list.length) defineSymbol(context, 'map', list.map) defineSymbol(context, 'build_list', list.build_list) @@ -98,20 +105,12 @@ export const importBuiltins = (context: Context) => { defineSymbol(context, 'member', list.member) defineSymbol(context, 'remove', list.remove) defineSymbol(context, 'remove_all', list.remove_all) + defineSymbol(context, 'equal', list.equal) + defineSymbol(context, 'assoc', list.assoc) defineSymbol(context, 'filter', list.filter) defineSymbol(context, 'enum_list', list.enum_list) defineSymbol(context, 'list_ref', list.list_ref) defineSymbol(context, 'accumulate', list.accumulate) - defineSymbol(context, 'equal', list.equal) - } - - if (context.chapter >= Infinity) { - // previously week 4 - defineSymbol(context, 'alert', alert) - defineSymbol(context, 'math_floor', Math.floor) - defineSymbol(context, 'timed', misc.timed) - // previously week 5 - defineSymbol(context, 'assoc', list.assoc) if (window.hasOwnProperty('ListVisualizer')) { defineSymbol(context, 'draw', (window as any).ListVisualizer.draw) } else { @@ -119,19 +118,22 @@ export const importBuiltins = (context: Context) => { throw new Error('List visualizer is not enabled') }) } - // previously week 6 + } + if (context.week >= 6) { defineSymbol(context, 'is_number', misc.is_number) - // previously week 8 + } + if (context.week >= 8) { defineSymbol(context, 'undefined', undefined) defineSymbol(context, 'set_head', list.set_head) defineSymbol(context, 'set_tail', list.set_tail) - // previously week 9 + } + if (context.week >= 9) { defineSymbol(context, 'array_length', misc.array_length) } } -const createContext = (chapter = 1, externals = []) => { - const context = createEmptyContext(chapter) +const createContext = (week = 3, externals = []) => { + const context = createEmptyContext(week) importBuiltins(context) importExternals(context, externals) diff --git a/src/slang/interop.ts b/src/slang/interop.ts index 45030dbd24..082b8a6985 100644 --- a/src/slang/interop.ts +++ b/src/slang/interop.ts @@ -1,7 +1,7 @@ import { generate } from 'astring' import { MAX_LIST_DISPLAY_LENGTH } from './constants' import { apply } from './interpreter' -import { ArrowClosure, Closure, Context, Value } from './types' +import { Closure, Context, Value } from './types' export const closureToJS = (value: Value, context: Context, klass: string) => { function DummyClass(this: Value) { @@ -30,7 +30,7 @@ export const closureToJS = (value: Value, context: Context, klass: string) => { } export const toJS = (value: Value, context: Context, klass?: string) => { - if (value instanceof Closure || value instanceof ArrowClosure) { + if (value instanceof Closure) { return value.fun } else { return value diff --git a/src/slang/parser.ts b/src/slang/parser.ts index dcfa02e1e0..e975b8c564 100644 --- a/src/slang/parser.ts +++ b/src/slang/parser.ts @@ -10,7 +10,7 @@ import { Context, ErrorSeverity, ErrorType, SourceError } from './types' // tslint:disable-next-line:interface-name export interface ParserOptions { - chapter: number + week: number } export class DisallowedConstructError implements SourceError { @@ -133,7 +133,7 @@ for (const type of Object.keys(syntaxTypes)) { usages: [] } context.cfg.edges[id] = [] - if (syntaxTypes[node.type] > context.chapter) { + if (syntaxTypes[node.type] > context.week) { context.errors.push(new DisallowedConstructError(node)) } } @@ -167,7 +167,7 @@ rules.forEach(rule => { const keys = Object.keys(rule.checkers) keys.forEach(key => { walkers[key] = compose(walkers[key], (node, context) => { - if (typeof rule.disableOn !== 'undefined' && context.chapter >= rule.disableOn) { + if (typeof rule.disableOn !== 'undefined' && context.week >= rule.disableOn) { return } const checker = rule.checkers[key] diff --git a/src/slang/syntaxTypes.ts b/src/slang/syntaxTypes.ts index 2ebbfb2c54..0efe756b42 100644 --- a/src/slang/syntaxTypes.ts +++ b/src/slang/syntaxTypes.ts @@ -1,40 +1,42 @@ const syntaxTypes: { [nodeName: string]: number } = { - // Chapter 1 - Program: 1, - ExpressionStatement: 1, - IfStatement: 1, - FunctionDeclaration: 1, - VariableDeclaration: 1, - ReturnStatement: 1, - CallExpression: 1, - UnaryExpression: 1, - BinaryExpression: 1, - LogicalExpression: 1, - ConditionalExpression: 1, - FunctionExpression: 1, - ArrowFunctionExpression: 1, - Identifier: 1, - Literal: 1, - - // Chapter 2 - ArrayExpression: 2, + // Week 3 + Program: 3, + ExpressionStatement: 3, + IfStatement: 3, + FunctionDeclaration: 3, + VariableDeclaration: 3, + ReturnStatement: 3, + CallExpression: 3, + UnaryExpression: 3, + BinaryExpression: 3, + LogicalExpression: 3, + ConditionalExpression: 3, + FunctionExpression: 3, + ArrowFunctionExpression: 3, + Identifier: 3, + Literal: 3, // Week 5 EmptyStatement: 5, - // preivously Week 8 + ArrayExpression: 5, + + // Week 8 AssignmentExpression: 8, WhileStatement: 8, - // previously Week 9 + + // Week 9 ForStatement: 9, BreakStatement: 9, ContinueStatement: 9, MemberExpression: 9, - // previously Week 10 + + // Week 10 ThisExpression: 10, ObjectExpression: 10, Property: 10, UpdateExpression: 10, NewExpression: 10, + // Disallowed Forever SwitchStatement: Infinity, DebuggerStatement: Infinity, diff --git a/src/slang/types.ts b/src/slang/types.ts index 338f44f985..6a9c186597 100644 --- a/src/slang/types.ts +++ b/src/slang/types.ts @@ -93,7 +93,7 @@ export interface TypeError extends SourceError { export interface Context { /** The source version used */ - chapter: number + week: number /** All the errors gathered */ errors: SourceError[]