Skip to content

Commit

Permalink
Merge pull request #116 from melnikga/feat-/List-of-Cairo-examples-to…
Browse files Browse the repository at this point in the history
…-select-from-

feat: List of Cairo examples to select from - Issue #109
  • Loading branch information
mazurroman authored Mar 21, 2024
2 parents 68363b8 + b3e965b commit 6d5ef26
Show file tree
Hide file tree
Showing 3 changed files with 253 additions and 7 deletions.
62 changes: 57 additions & 5 deletions components/Editor/EditorControls.tsx
Original file line number Diff line number Diff line change
@@ -1,15 +1,26 @@
import { useRef } from 'react'
import { useMemo, useRef, useId } from 'react'

import { RiLinksLine, RiQuestionLine } from '@remixicon/react'
import cn from 'classnames'
import { Priority, useRegisterActions } from 'kbar'
import Select, { OnChangeValue } from 'react-select'
import examples from 'components/Editor/examples'

import { Button, Input } from 'components/ui'

type SelectOption = {
value: number
label: string
}

type EditorControlsProps = {
isCompileDisabled: boolean
programArguments: string
areProgramArgumentsValid: boolean
exampleName: number
handleChangeExampleOption: (
option: OnChangeValue<SelectOption, false>,
) => void
onCopyPermalink: () => void
onCompileRun: () => void
onProgramArgumentsUpdate: (args: string) => void
Expand All @@ -20,6 +31,8 @@ const EditorControls = ({
isCompileDisabled,
programArguments,
areProgramArgumentsValid,
exampleName,
handleChangeExampleOption,
onCopyPermalink,
onCompileRun,
onProgramArgumentsUpdate,
Expand Down Expand Up @@ -56,6 +69,33 @@ const EditorControls = ({

useRegisterActions(actions, [onCompileRun, onCopyPermalink])

const CairoNameExamples = useMemo(
() => [
'Default',
'Variables & mutability',
'Type casting',
'Control flow',
'Functions',
'Arrays',
'Dictionaries',
'Ownership',
],
[],
)

const examplesOptions = examples.Cairo.map((example, i) => ({
value: i,
label: CairoNameExamples[i],
}))

const exampleNameValue = useMemo(
() => ({
value: exampleName,
label: CairoNameExamples[exampleName],
}),
[CairoNameExamples, exampleName],
)

return (
<div className="flex flex-col md:flex-row md:items-center md:justify-between gap-x-4 px-4 py-4 md:py-2 md:border-r border-gray-200 dark:border-black-500">
<div className="flex flex-col md:flex-row md:gap-x-4 gap-y-2 md:gap-y-0 mb-4 md:mb-0">
Expand All @@ -71,7 +111,18 @@ const EditorControls = ({
</span>
</Button>
</div>

<div className="w-full md:w-60 lg:mr-20">
<Select
isSearchable={false}
classNamePrefix="select"
menuPlacement="auto"
value={exampleNameValue}
options={examplesOptions}
instanceId={useId()}
onChange={handleChangeExampleOption}
isDisabled={isCompileDisabled}
/>
</div>
<Input
ref={inputRef}
rightIcon={
Expand All @@ -87,23 +138,24 @@ const EditorControls = ({
}}
readOnly={isCompileDisabled}
value={programArguments}
placeholder={`Enter program arguments...`}
className={cn('grow border bg-gray-200 dark:bg-gray-800', {
placeholder={`Program arguments`}
className={cn('grow border bg-gray-200 dark:bg-gray-800 ', {
'dark:border-gray-800 border-gray-200': areProgramArgumentsValid,
'border-red-500': !areProgramArgumentsValid,
})}
inputClassName={cn({
'text-red-500': !areProgramArgumentsValid,
})}
/>

<div>
<Button
onClick={onCompileRun}
disabled={isCompileDisabled || !areProgramArgumentsValid}
size="sm"
contentClassName="justify-center"
>
Compile and run
Run
</Button>
</div>
</div>
Expand Down
187 changes: 187 additions & 0 deletions components/Editor/examples.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,193 @@ const examples: ExampleCode = {
fn main() -> felt252 {
let n = 2 + 3;
n
}`,
`use core::felt252;
const my_constant: felt252 = 42;
fn main() {
// non-mutable variable
let my_var = 12;
println!("{my_var}");
// my_var = 38; <-- fails to compile
// variable shadowing (declare another variable with the same name)
let my_var = 'hello world';
println!("{my_var}");
// mutable variable
let mut my_mut_var = 10;
my_mut_var = my_mut_var * 2;
println!("{my_mut_var}");
// my_mut_var = 'hello world' <-- fails to compile
}`,
`use core::felt252;
fn main() {
let my_felt252 = 10;
// Since a felt252 might not fit in a u8, we need to unwrap the Option<T> type
let my_u8: u8 = my_felt252.try_into().unwrap();
let my_u16: u16 = my_u8.into();
let my_u32: u32 = my_u16.into();
let my_u64: u64 = my_u32.into();
let _my_u128: u128 = my_u64.into();
// As a felt252 is smaller than a u256, we can use the into() method
let _my_u256: u256 = my_felt252.into();
let _my_usize: usize = my_felt252.try_into().unwrap();
let _my_other_felt252: felt252 = my_u8.into();
let _my_third_felt252: felt252 = my_u16.into();
}`,
`#[derive(Drop)]
enum Direction {
Up,
Down,
Left,
Right
}
fn main() {
// if / else expression
let x = 10;
let y = 20;
if x == y {
println!("x == y");
}
else {
println!("x != y");
};
// if with return value
let _res = if x == y {
'equal'
}
else {
'not_equal'
};
// match expression (with some limitations in Cairo <= 2.5)
let x = Direction::Up;
match x {
Direction::Up => println!("you win !"),
_ => println!("you loose ...")
}
// match expression with return value
let x = Direction::Down;
let _res = match x {
Direction::Up => 1,
Direction::Down => -1,
Direction::Left => -1,
Direction::Right => 1,
};
// loop expression
let mut i: u128 = 0;
loop {
if i > 9 { // Break condition
break;
}
i = i + 1;
};
// loop with return value
let _res = loop {
if i > 9 { break (42); }
i = i + 1;
};
}`,
`// This function returns an u32.
fn add(a: u32, b: u32) -> u64 {
// there is no semi-colon at the end so the
// result of this expression is returned.
// equivalent to: return x + 1;
a.into() + b.into()
}
// This functions doesn't return anything.
fn main() {
let a = 1;
let b = 2;
let x = 3;
let y = 4;
// named parameters to be more explicit
let _c = add(:a, :b);
let _z = add(a: x, b: y);
}
`,
`use array::ArrayTrait;
fn main () {
let mut a = ArrayTrait::new();
// add some items in the array
a.append(1);
a.append(2);
// get array length
assert!(a.len() == 2, "wrong array length");
// 2 ways to read an item from the array
// * get() returns an Option so you can handle out-of-bounds error
// * at() panics in case of out-of-bounds error
let first_element = *a.get(0).unwrap().unbox();
// a.get(2) will return None
let second_element = *a.at(1);
// a.at(2) will cause an error
}`,
`fn main () {
let mut balances: Felt252Dict<u64> = Default::default();
balances.insert('Alex', 100);
balances.insert('Maria', 200);
let alex_balance = balances.get('Alex');
assert!(alex_balance == 100, "Balance is not 100");
let maria_balance = balances.get('Maria');
assert!(maria_balance == 200, "Balance is not 200");
}`,
`use array::ArrayTrait;
fn foo_takes_ownership(arr: Array<u128>) {
// foo takes ownership of the array.
// when this function returns, arr is dropped.
}
fn foo_receives_ref(ref arr: Array<u128>) {
// receives a ref to an array so the calling function
// keeps the ownership of the array.
}
fn main() {
// as the creator of arr, the main function owns the array
let mut arr = ArrayTrait::<u128>::new();
foo_takes_ownership(arr); // moves ownership of the array to function call
// foo(arr); // <- fails to compile, as main doesn't own the array anymore
let mut another_arr = ArrayTrait::<u128>::new();
foo_receives_ref(ref another_arr);
foo_receives_ref(ref another_arr); // no compilation issue, main still owns another_arr
}`,
],
Sierra: [
Expand Down
11 changes: 9 additions & 2 deletions components/Editor/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,7 @@ const Editor = ({ readOnly = false }: Props) => {
const { addToConsoleLog } = useContext(AppUiContext)

const [cairoCode, setCairoCode] = useState('')
const [exampleOption, setExampleOption] = useState<number>(0)
const [codeType, setCodeType] = useState<string | undefined>()
const [programArguments, setProgramArguments] = useState<string>('')

Expand All @@ -90,10 +91,10 @@ const Editor = ({ readOnly = false }: Props) => {
getSetting(Setting.EditorCodeType) || CodeType.Cairo

setCodeType(initialCodeType)
setCairoCode(examples[initialCodeType][0])
setCairoCode(examples[initialCodeType][exampleOption])
}
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [settingsLoaded && router.isReady])
}, [settingsLoaded && router.isReady, exampleOption])

useEffect(() => {
if (compilationState === ProgramCompilationState.Compiling) {
Expand Down Expand Up @@ -384,6 +385,12 @@ const Editor = ({ readOnly = false }: Props) => {
onProgramArgumentsUpdate={handleProgramArgumentsUpdate}
onCompileRun={handleCompileRun}
onShowArgumentsHelper={() => setShowArgumentsHelper(true)}
exampleName={exampleOption}
handleChangeExampleOption={(newExample) =>
newExample !== null
? setExampleOption(newExample.value)
: setExampleOption(0)
}
/>
</div>

Expand Down

0 comments on commit 6d5ef26

Please sign in to comment.